常数操作(固定时间):如加减乘除运算,位运算,赋值运算,寻址操作(数组寻址)。
非常数操作(不是固定时间):如单链表(linkedList),没办法算偏移量。(在链表中使用for(){list.get[i]} -> 这个就是O(N^2) )。
评估算法优劣的核心指标是什么?
1)时间复杂度
2)额外空间复杂度
3)常数项时间(细节决定)
复杂度
时间复杂度:把算法流程分解成常数时间的操作,
选择排序
1)
①N个数看一遍(N次),找最小值(N -1 次比较)。
②最小值放0位置(一次交换)。
2)
①N - 1个数看一遍(N - 1次),找最小值(N -2 次比较)。
②最小值放0位置(一次交换)。
3)
等等…
看 + 比较 = aN^2 + bN + c ;(a,b,c 都是常数)
复杂度只要最高阶项
冒泡排序
N 个数之间交换 O(1)
N - 1 个数之间交换
N - 2 个数之间交换
…………
等差数列,直接O(N^2)
插入排序
直到前面没数了或者左边数不比你大了停止
数组:[2,3,3,1,4,0]
1)0~0有序,这是肯定的
2)0~1有序,盯着1位置的数字,大就交换
3)0~2有序,盯着2看,向前比较,大就交换
4)…………
最好情况是 O(N) ,最坏是 O(N^2)。
取最差情况!!! 即时间复杂度也是O(N^2)
额外空间复杂度
看额外开辟空间是否是常数,若是数组,或是一张表,就是O(N),要是只用固定的几个变量,就是O(1)。看具体功能需求,要是要求拷贝数租,这个不算做额外空间。
算法流程的常数项
当两个都是O(N^2)算法,复杂度已经比较不出来了,继续PK,要拼常数相比较。
比如冒泡和插入,一定是插入更好!
放弃理论,直接生成随机数据进行分析。
加减乘除没有位运算快。
面试刷题中,什么是最优解?
先保证时间复杂度尽量低,再尽可能优化空间复杂度降低。不用关心常数项。
常用时间复杂度排名
O(1),O(logN),O(N),O(N*logN),O(n^2), O(N^3), O(N^k)
O(2^n) ,O(3^n), O(K^n) -> 这三个一般是递归用到。
算法和数据结构学习的大脉络
1)知道怎么算的算法
2)知道怎么试的算法
认识二分法
常见题型:
1)一个有序数组中找某个数是否存在?
如果用遍历是O(N)—最差情况。
二分是O(logN)
2)在一个有序数组中找到 >= 某个数最左侧的位置?返回索引
准备一个中间变量mid,mid = L + ((R - L ) / 2),这样写防止溢出,更安全。要是L + R,R 和 L 特别大的时候可能会溢出。
N / 2 == N >> 1 , mid = L + ((R - L ) >> 1),反之乘二左移一位。
while(L < R){
...
}
return sortedArr[L] == num;
while的条件是(L < R),即至少存在两个数才执行循环
最后再去验证最后一个数是否是要找的数。
3)在一个有序数组中找到 <= 某个数最右侧侧的位置?
4)局部最小值问题
问题:在一个无序数组中,值随意,任意两个相邻的数不相等
局部最小是指:[0] < [1],[N - 2] > [N - 1] ,[i - 1] > [i] < [i + 1] ,只要找到一个局部最小就行。
先看[0] < [1],要是符合直接返回 [0];
再看[N - 2] > [N - 1],要是符合直接返回 [N - 1];
否则,二分!!
找中点mid,mid要是符合[i - 1] > [i] < [i + 1],返回 [mid];不符合随便找一侧二分,在比较是否符合!!!
二分法不一定要有序,题目要求要是 能排他的话,类似这个情况既可以二分。
认识异位运算
异或运算:相同为零,不同为一。(可以理解为二进制的无进位相加。)
同或运算:相反。
1)0^N = N
2)N^N = 0;
3)异位运算满足交换律和结合律
题目一:
如何不用额外变量交换链两个数?
要是用临时变量要申请额外空间 int temp;
不用临时变量交换:
a = a ^ b;
b = a ^ b;
a = a ^ b;
题目二:
在数组中有一种数出现了奇数次,其他数出现了偶数次,找到并打印这个数字?
很简单!!!一行代码,全都异或!!!
int eor = 0;
for(int i = 0; i < arr.length; i++){
eor ^= arr[i];
}
sout(eor);
题目三:
怎么把一个int类型的数,提取出二进制形式下最右边的 1 ?
a ^ (~a + 1) 或者 a ^ ( -a ) ;
得出 ~a + 1 == - a ;
题目四:
一个数组中有两种数出现了奇数次,其他数出现了偶数次,找到并打印这两种数?
思路:
假设这两个数字是a,b
1)引入一个变量 eor,eor 从头异或到尾,eor = a ^ b;因为a,b不相等,所以 eor 不等于零,不妨设 eor 第三位这个位置一定有个1,所以a和b第三位的二进制数字不相等。
2)所有的数字都可以分为两类,一种是第三位是1的,一种是不是1的,假设a在第三位是1的类别中,那么b一定在不是1的类别中。
3)再申请一个 eor’ 变量,让eor’去和第三位是1的类别中遍历异或,最后一定得到 a,另一个数就是 eor ^ eor’
题目五:
一个数组中有一种数出现了K次,其他数出现了M次,M >1 ,K < M,找到出现了K次的数?(要求:额外空间复杂度O(1),时间复杂度O(N))