1.时间复杂度:
时间复杂度为一个(默认最差情况下)算法流程中, 常数操作数量的指标。 常用O(读作big O) 来表示。 具体来说, 在常数操作数量的表达式中,
只要高阶项, 不要低阶项, 也不要高阶项的系数, 剩下的部分 如果记为f(N), 那么时间复杂度为O(f(N))。
先看时间复杂度的指标, 然后再分析不同数据样本下的实际运行时间
2.冒泡排序:时间复杂度 O(N^2)
2.1 每个数和它后面的一个数进行比较,这个数比后面的数大则进行交换。
2.2 这样最后一个数会是最大的。
2.3 每次都这样,但是最后一个数不需要再进行比较了
2.4 代码:
int[] a = new int[]{1,5,4,3,2,6};
int end = a.length-1;
for(int i=end;i>0;i--)
for(int j=0;j<i;j++){ //每次排序少一个数
int temp=0;
if(a[j]>a[j+1]){
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
3.选择排序:时间复杂度 O(N^2)
3.1 遍历一次数组,将最小的索引保存下来
3.2 让第一个数和这个索引数进行交换
3.3 每次少遍历一个数
3.4 代码:O(N*N)
int[] a = new int[]{1,5,4,3,2,6};
for(int i=0;i<a.length;i++){
int minindex =i;
for(int j=i+1;j<a.length;j++){
if(a[minindex]>a[j]){
minindex = j;
}
}
int temp = a[minindex];
a[minindex] = a[i];
a[i] = temp;
}
4.插入排序:
4.1 第一个数和第二个数比较,比第二个数大的话,进行交换
4.2 第二个数和第三个数进行比较,大的话进行交换,交换后再比较。
4.3 如果这个数已经比前一个数大了,那就不需要再进行比较了,因为前面已经比较好了
4.3 代码:
int[] a = new int[]{1,5,4,3,2,6};
for(int i=1;i<a.length;i++)
for(int j=i-1;j>=0&&a[j]>a[j+1];j--){ //关键代码,当a[j]>a[j+1],退出循环
int temp = a[j];
a[j] = a[j+1];
a[j+1]=temp;
}
5.对数器:
5.1 实现一个绝对正确的方法
5.2 实现一个随机样本数
5.3 实现一个对比的方法
5.4 将想测的方法和绝对正确的方法的结果进行比较。
5.5 将错的数组,还有不同方法的结果打印出来进行对比
6. 递归的复杂度分析
T(N) = a*T(N/b) + O(N^d)
a表示子过程发生多少次
N/b 表示子过程的样本量
O(n的d次方) 表示除了子过程剩下的内容
1) log(b,a) > d -> 复杂度为O(N^log(b,a)) 以b为底
2) log(b,a) = d -> 复杂度为O(N^d * logN)
3) log(b,a) < d -> 复杂度为O(N^d)
7. 归并排序
7.1 先将数组二分排序
7.2 现在我们有一个数组,但是前面和后面部分都已经排好序,设定两个变量a,b,分别保存数组的索引
7.3 新建一个数组,将两部分的元素进行比较,谁大,保存到数组中,并使a或者b,自加
7.4 当a或者b达到了各自的末尾时,将剩余部分copy到数组中
7.5 再讲此数组copy到原数组。
public static void mergeSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
mergeSort(arr, 0, arr.length - 1);
}
public static void mergeSort(int[] arr, int l, int r) {
if (l == r) {
return;
}
int mid = (l+r)/2;
mergeSort(arr,l,mid);
mergeSort(arr,mid+1,r);
merge(arr,l,mid,r);
}
public static void merge(int[] arr, int l, int m, int r) {
int p1 = l;
int p2 = m + 1;
int[] help = new int[r-l+1];
int i = 0;
while (p1<=m&&p2<=r){
if(arr[p1]<arr[p2]){
help[i++] = arr[p1++];
}
else
help[i++] = arr[p2++];
}
while (p1<=m){
help[i++]=arr[p1++];
}
while (p2<=r){
help[i++]=arr[p2++];
}
for(i=0;i<r-l+1;i++){
arr[l+i]=help[i];
}
}
8. 小和问题:
在一个数组中, 每一个数左边比当前数小的数累加起来, 叫做这个数组的小和。 求一个数组的小和
8.1 利用归并排序。把数据一块一块处理。
8.2 有两块数据,前面的数组起始下标为a,后面的数组起始下标为b。
8.3 判断大小,小的话,后面的数量乘以a下标的值,因为后面的每一个数都比b大。
8.4 用归并排序能够降低时间复杂度。
9. 位运算
mid = (R+L)/2 R+L可能会导致溢出。
mid = L + (R-L)>>1 此式与上式效果一致,但能节省时间,并防止溢出。