本文已参与[新人创作礼]活动,一起开启掘金创作之路
大O表示法
O(n^2 / n^3) ...
O(n*logn)
O(n)
线性增长, 斜率为n
-
示例,计算i = 0, 到 i = n 时,i^3 积分
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 size_t sum(int n) 5 { 6 size_t res = 0; 7 8 for (int i = 1; i <= n; i++) 9 res += i * i * i; 10 11 return res; 12 } 13 14 int main(int argc, char** argv) 15 { 16 if (argv[1] == 0) 17 argv[1] = "1"; 18 19 int n = atoi(argv[1]); 20 21 printf("%ld\n", sum(n)); 22 23 return 0; 24 }gcc -std=gnu11 -g -O0 cal.c -o cal.out
第9行有两次乘积,一次加法,一次赋值,5次,第8行有一次加法,一次比较,第一行,第六行也有时间开销,大致为7n+2,为线性增加
- 推理
- 一阶循环
- O(n)
- 二阶循环
- O(n^2)
for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) res += j;
- 一阶循环
- 递归的时间复杂度分析
- 斐波那契计算
size_t fab(int n) { if (n <= 1) return 1; else return fab(n - 1); }- 时间复杂度为O(n),随着n的递增,递归迭代的次数同步递增,斜率为n
- 另一个递归
size_t fun(int n) { if (n <= 1) return 1; else return fun(n - 1) + fun(n - 2); }- 随着n的增加,每次迭代多了两次,迭代次数为 1, 3, 7, 15...,复杂度为O(n^2)
- 该算法的问题在于,有重复的算法,如计算fun(n - 1) + fun(n - 2)时,fun(n - 1)会再次计算一遍fun(n - 2)
- 斐波那契计算
最大子序列的4种算法
参考 CSDN 最大子序列和的四种算法,代码拷贝来自此处
算法思想,已知一个有符号位整数数组,a[n],求在整个数组空间中,哪一段连续空间可以得到最大值
数组内可能有负数,所有整个数组的空间内所有数之和并不一定是最大数,哪一段空间内有可能求和最大都有可能
-
暴力求解
public static int maxSubSum1(int[] a) { int maxSum = 0; int sum; for (int i = 0; i < a.length; i++) { for (int j = i; j < a.length; j++) { sum = 0; for (int k = i; k <= j; k++) { sum += a[k];// 计算a[i]到a[j]的和 } if (sum > maxSum) { maxSum = sum; } } } return maxSum; }- 时间复杂度 O(n^3)
-
初次简化
- 在 i 不变时,j 的每次增加,其实都会用到上次 i 到 j - 1 的结果
public static int maxSubSum2(int[] a) { int maxSum = 0; int sum; for (int i = 0; i < a.length; i++) { sum = 0; for (int j = i; j < a.length; j++) { sum += a[j]; if (sum > maxSum) { maxSum = sum; } } } return maxSum; }- 时间复杂度 O(n^2)
-
分支法,最大值一定出现在左侧或右侧
- 太麻烦,没看
-
最优起点
- 算法思想:设a[i]为和最大序列的起点,则如果a[i]是负的,那么它不可能代表最优序列的起点,因为任何包含a[i]作为起点的子序列都可以通过a[i+1]作起点而得到改进。类似的,任何负的子序列也不可能是最优子序列的前缀。
public static int maxSubSum4(int[] a){ int maxSum=0,sum=0; for(int i=0;i<a.length;i++){ sum+=a[i]; if(sum>maxSum){ maxSum=sum; }else if(sum<0){ sum=0; } } return maxSum; }- 运行时间:O(N)
最优起点算法的特点
- 没有递归,不容易跑飞
- 不需要大容量存储
- 一次遍历即可
- 对给定数组的“兼容性”强
O(logn)型
二分法求坐标
一直一个已经排序的数组a[n],求a[i] = X 的坐标i,如果没有返回-1
方法:先假设i处于数组中间,如果是,返回该下表,如果不是,重新设定数组为当前已被分割的数组的左半部分或右半部分
最大公因数 欧几里得算法
算法原理不好讲,可能是数学方便,不懂,不看
幂运算
- 算法
size_t pow(int x, int n) { if (n == 0) return 1; else if (n == 1) return x; else if (n % 2 == 1) return pow(x * x, n / 2) * x; else return pow(x * x, n / 2); }- 特点
- 一次递归只有一个分支
- 递归操退出方向前进
- n的收敛速度很快
- 特点
课后习题
2.6
- O(n),n = 1,直线
- O(n^2),n^2,2次方
- O(n^3),n^3,3次方
- O(n^2),n^2,2次方,猜测
- 往后不会,猜测