算法相关的一些基础知识
B站左神之前牛客网直播的教程 时间复杂度,递归,对数器等基础知识点
认识时间复杂度
时间复杂度为一个算法流程中,常数操作数量的一个指标。常用O(读作big O)来表示。具体 来说,先要对一个算法流程非常熟悉,然后去写出这个算法流程中,发生了多少常数操作, 进而总结出常数操作数量的表达式。
在表达式中,只要高阶项,不要低阶项,也不要高阶项的系数,剩下的部分如果为f(N),那 么时间复杂度为O(f(N))。
评价一个算法流程的好坏,先看时间复杂度的指标,然后再分析不同数据样本下的实际运行 时间,也就是“常数项时间”。
常数操作
一个操作如果和样本的数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作。例如+-*/
异或运算
- 0^N == N N^N == 0
- 异或运算满足交换律和结合率
- 不用额外变量交换两个数
- 一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到这一个数
- 一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到这两个数
a、b在内存中是两块独立的区域时(分别指向不同的内存):↓
异或面试题
1) 数组里有一种数出现了奇数次,其他数出现了偶数次
2) 数组里有两种数出现了奇数次,其他数偶数次
1的解法
public static void printOddTimesNum1(int[] arr) {
int eO = 0;
for (int cur : arr) {
eO ^= cur;
}
System.out.println(eO);
}
异或运算跟顺序没关系,跟1出现的次数有关(偶奇数)用无进位相加来理解
2的解法
eor 异或所有数
eor’ 只异或 第n位不为1的数
然后将eor^eor'
public static void printOddTimesNum2(int[] arr) {
int eO = 0, eOhasOne = 0;
for (int curNum : arr) {
eO ^= curNum;
}
int rightOne = eO & (~eO + 1);
for (int cur : arr) {
if ((cur & rightOne) != 0) {
eOhasOne ^= cur;
}
}
System.out.println(eOhasOne + " " + (eO ^ eOhasOne));
}
提取最右的1
对数器
对数器的概念和使用
- 有一个你想要测的方法a
- 实现复杂度不好但是容易实现的方法b
- 实现一个随机样本产生器 4,把方法a和方法b跑相同的随机样本,看看得到的结果是否一样
- 如果有一个随机样本使得比对结果不一致,打印样本进行人工干预,改对方法a或者 方法b
- 当样本数量很多时比对测试依然正确,可以确定方法a已经正确。
递归
public static int getMax(int[] arr) {
return process(arr, 0, arr.length - 1);
}
public static int process(int[] arr, int L, int R) {
if (L == R) {
return arr[L];
}
int mid = L + ((R - L) >> 1);
int leftMax = process(arr, L, mid);
int rightMax = process(arr, mid + 1, R);
return Math.max(leftMax, rightMax);
}
master 公式
用递归方法找一个数组中的最大值,系统上到底是怎么做的? master公式的使用
T(N) = a*T(N/b) + O(N^d)
- log(b,a) > d -> 复杂度为O(N^log(b,a))
- log(b,a) = d -> 复杂度为O(N^d * logN)
- log(b,a) < d -> 复杂度为O(N^d)
补充阅读:www.gocalf.com/blog/algorithm-complexity-and-master- theorem.html
子问题必须等规模
1/2 + 1/2 行
1/3 + 2/3 不行
比较器
- 比较器的实质就是重载比较运算符
- 比较器可以很好的应用在特殊标准的排序上
- 比较器可以很好的应用在根据特殊标准排序的结构上