1、认识时间复杂度
指在一个算法中,执行完所需要多少次常数级操作。
用O来表示,如:O(n)、O(n^2)、O(n^3)等.
由于时间复杂度不仅仅和算法本身有关,还与给定的数据有关,所以我们这边一般指的是最差情况下的时间复杂度。
当然还包含一些使用数学期望作为时间复杂度的算法,如:随机快排
1.1 常数级别操作
常数级操作是指语言中,可执行的最小指令单元。
包含: +-*/~ ^ & | >> >>> << <<<
^ (亦或)
可以按照不进行进位的加法来计算。如:1^1,二进制中 1+1=10,那么不进位就是0 1^0=1
0^0=0
1^1=0
0^n=n
n^n=0
满足交换律:a^b^c^d=d^c^b^a
满足结合律:(a^b)^(c^d)=a^b^c^d
一个整数序列中,除了x有技术个,其他数都是偶数个存在,求出x是什么数。利用上述特性,将数组内所有数都进行亦或计算,最后的结果就是x。
& (且)
判断偶数:n&1 ==0
整数n,二进制下最右边1的位置: n&(~n+1)
整数数组中,值存在a、b两个整数是奇数个,其他数都是偶数个,找出a、b的值。
将所有数进行亦或:a1^a2^a3^a4……^an = a^b = n
n&(~n+1) = x 找出最右边1的位置下标i
int p=0
for n in arr{
if ai & n ==0{
p=p^ai
}
}
a=p
b=n^p
递归复杂度计算
子函数规模固定的递归,时间复杂度公式: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)
log(b,a)==d O(n^d * log(b,a))
2、排序算法
选择排序
O(n^2)
冒泡排序
O(n^2)
插入排序
O(n^2)
归并排序
O(n*logn)
随机快排
partion(分区)
/**
* 分区 将数组中 给定的区域L-R 按照给定的num进行划分
* 左区为 <num
* 右区为 >num
* 中间为 =num
*/
public static int[] partition(int[] arr, int L, int R, int num){
int lessIndex = L -1;
int greatIndex = R+1;
for (int i =L;i>lessIndex && i<greatIndex; ){
int curNum = arr[i];
if(curNum == num){
i++;
continue;
}else if(curNum < num){
swap(arr, ++lessIndex, i);
i++;
}else {
swap(arr, --greatIndex, i);
}
}
return new int[]{lessIndex, greatIndex};
}
快排
O(n*logn)
public static void quickSort(int arr[]){
quickSort(arr, 0, arr.length -1, randomIndex(0, arr.length -1));
}
public static void quickSort(int[] arr, int L, int R, int num){
if(L>=R){
return;
}
int[] result = partition(arr, L, R, num);
int lessI = result[0], greatI = result[1];
quickSort(arr, L, lessI, randomIndex(L, lessI));
quickSort(arr, greatI, R, randomIndex(greatI, R));
}
堆排序
O(n*logn)
大根堆
完全二叉树的每一个父节点,比他的子节点的值都大。
小根堆
完全二叉树的每一个父节点,比他的子节点的值都小。