2.算法复杂度问题
大约 4 分钟
2.算法复杂度问题
时间复杂度
这里主要总结数据结构中时间复杂度的计算方法,在学习过程中,参考了B站的数据结构——时间复杂度计算这个视频,可以在看完视频后,再阅读本文,效果更佳。
根据循环的层次不同,分为三个类别:
- 单层循环
- 两层循环
- 多层循环
这里一一进行说明。
1.单层循环
解决思路
- 列出循环次数 t 以及每轮循环的变化值。
- 找到 t 与 i 的关系
- 确定循环的停止条件。
- 联立两式,解方程。
- 写结果。
单层循环相对来讲是比较简单的,但是这里还是想整理成方法论,在做题过程中,不容易出错。下面我们来具体举例说明。
例子1:简单
int func(int n){
int i = 0;
while (i < n){
i ++;
}
return i;
}
我们根据方法论,具体操作如下:
- 列出循环次数 t 以及每轮循环的变化值。
t | 0 | 1 | 2 | 3 | ... | k |
---|---|---|---|---|---|---|
i | 0 | 1 | 2 | 3 | ... | n - 1 |
- 找到 t 与 i 的关系
此时 t 和 i 的关系式为 i = t
- 确定循环的停止条件。
循环结束的条件为,i = n
- 联立两式,解方程。
联立即可得到 t = n
- 写结果
即一共循环了 n 次
例子2:中等难度
int func(int n){
int i = n * n;
while (i != 1){
i /= 2;
}
return i;
}
同样,我们根据方法论的步骤进行解答:
- 列出循环次数 t 以及每轮循环的变化值。
t | 0 | 1 | 2 | 3 | ... | k |
---|---|---|---|---|---|---|
i | ... |
- 找到 t 与 i 的关系
i =
- 确定循环的停止条件。
当 i = 1 时退出循环
- 联立两式,解方程。
i = = 1 , 解得 k =
- 写结果。
那么对应的时间复杂度就是 O()
例子3:较难
int func(int n){
int i = 0;
int sum = 0;
while (sum < n){
sum += ++i;
// 这里实际上就可以拆分为两条语句。
// 1. ++i; 这里是先 ++ 再返回。
// 2. sum = sum + i;
}
return i;
}
- 列出循环次数 t 以及每轮循环的变化值。
t | 0 | 1 | 2 | 3 | ... | T |
---|---|---|---|---|---|---|
i | 0 | 1 | 2 | 3 | ... | I |
sum | 0 | 1 | 3 | 6 | ... |
- 找到 t 与 i 的关系
t = i
- 确定循环的停止条件。
sum >= n
- 联立两式,解方程。
- 写结果。
t = i,则对应的时间复杂度为 O()
2.两层循环
解题思路
- 列出外层循环中 i 的变化量。
- 列出内层语句的执行次数。
- 求和,写结果。
例子1
int func(int n,int m){
for(int i = 0;i < n;i ++){
for(int j = 0;j < m;j ++){
arr[i][j] = 0;
}
}
return n * m;
}
- 列出外层循环中 i 的变化量。
和步骤2合并一起
- 列出内层语句的执行次数。
i | 0 | 1 | 2 | 3 | ... | n - 1 |
---|---|---|---|---|---|---|
j | m | m | m | m | ... | m |
- 求和,写结果。
一共执行的次数T = [(n - 1) - 0 + 1] * m = n * m;
对应的时间复杂度为 O(nm)
例子2
int func(int n){
for(int i = 0;i < n;i ++){
for(int j = 0;j < i;j ++){
arr[i][j] = 0;
}
}
return n;
}
- 列出外层循环中 i 的变化量。
和步骤2合并一起
- 列出内层语句的执行次数。
i | 0 | 1 | 2 | 3 | ... | n - 1 |
---|---|---|---|---|---|---|
j | 0 | 1 | 2 | 3 | ... | i |
- 求和,写结果。
一共执行的次数 $ T = \frac {n * [0 + (n - 1)]} {2} $
则对应的时间复杂度
3.三层循环
解题思路
- 方法1: 抽象为计算三维体积
- 方法2: 列式求和
例子
int func(int n){
for(int i = 1;i <= n;i ++){
for(int j = 1;j <= i;j++){
for(int k = 1;k <= j;k++){
arr[i][j][k] = 0;
}
}
}
return n;
}
第一种方法我目前也没有理解,具体是怎么做的。
体积公式
第二种方法:
则对应的时间复杂度为
空间复杂度
空间复杂度是很容易判断的,这里主要对递归操作进行说明。
每次递归时,调用一次递归函数,则为
每次递归时,调用两次递归函数,则为
......
以此类推即可。