算法时间复杂度详解
1. 什么是时间复杂度
时间复杂度(Time Complexity)用于描述算法执行次数随数据规模 n 增长的变化趋势,而不是程序实际运行时间。
例如:
for (int i = 0; i < n; i++) {
cout << i;
}
循环执行 n 次,因此时间复杂度为:
O(n)
时间复杂度关注的是增长趋势,而不是具体耗时。
2. 大 O 表示法
忽略常数
O(3n)→O(n)O(100n)→O(n)
忽略低阶项
O(n²+n)→O(n²)O(n³+n²+n)→O(n³)
3. 常见复杂度
| O(1) | 常数 | ★★★★★ |
| O(log n) | 对数 | ★★★★★ |
| O(√n) | 平方根 | ★★★★☆ |
| O(n) | 线性 | ★★★★ |
| O(n log n) | 线性对数 | ★★★ |
| O(n²) | 平方 | ★★ |
| O(n³) | 立方 | ★ |
| O(2ⁿ) | 指数 | 极慢 |
| O(n!) | 阶乘 | 几乎不可用 |
4. 如何计算时间复杂度
4.1 基本语句
a++;
执行一次,因此:
O(1)
4.2 顺序结构
复杂度相加,保留最高阶。
例如:
for (...) {}
for (...) {}
总复杂度:
O(n)+O(n)=O(n)
若为:
O(n²)+O(n)=O(n²)
4.3 单层循环
for(int i=0;i<n;i++)
复杂度:
O(n)
若循环到 n/2:
for(int i=0;i<n/2;i++)
仍为:
O(n)
固定循环 100 次:
for(int i=0;i<100;i++)
复杂度:
O(1)
4.4 嵌套循环
两层:
for(...)
for(...)
复杂度:
O(n²)
三层:
O(n³)
4.5 循环次数变化
for(i=0;i<n;i++)
for(j=0;j<i;j++)
执行次数:
0+1+2+...+(n-1)
根据公式:
n(n-1)/2
因此:
O(n²)
4.6 每次翻倍或减半
for(int i=1;i<n;i*=2)
或:
while(n>1)
n/=2;
复杂度:
O(log n)
4.7 n × log n
for(...)
while(...)
若:
- 外层:O(n)
- 内层:O(log n)
总复杂度:
O(n log n)
4.8 递归
线性递归
T(n)=T(n-1)+O(1)
复杂度:
O(n)
对数递归
T(n)=T(n/2)+O(1)
复杂度:
O(log n)
主定理常见结论
| T(n)=2T(n/2)+O(1) | O(n) |
| T(n)=2T(n/2)+O(n) | O(n log n) |
| T(n)=2T(n-1)+O(1) | O(2ⁿ) |
5. 经典例题
例1
for(i=0;i<n;i++)
答案:
O(n)
例2
for(i=0;i<n;i++)
for(j=0;j<n;j++)
答案:
O(n²)
例3
for(i=1;i<n;i*=2)
答案:
O(log n)
例4
for(i=0;i<n;i++)
for(j=1;j<n;j*=2)
答案:
O(n log n)
例5
for(i=0;i<n;i++)
for(j=i;j<n;j++)
执行次数:
n+(n-1)+...+1
复杂度:
O(n²)
6. 分析口诀
- 基本语句:O(1)
- 顺序结构:相加取最高阶
- 嵌套循环:复杂度相乘
- 每次加减常数:通常 O(n)
- 每次乘除常数:通常 O(log n)
- 求和型循环:先求执行次数再化简
- 递归:写递推式,再分析
7. 速查表
| 常数操作 | O(1) |
| 每次翻倍/减半 | O(log n) |
| 固定次数循环 | O(1) |
| 单层循环 | O(n) |
| 循环到 n/2 | O(n) |
| 外层 n、内层 log n | O(n log n) |
| 双重循环 | O(n²) |
| 0+1+…+n | O(n²) |
| 三重循环 | O(n³) |
| T(n)=T(n/2)+O(1) | O(log n) |
| T(n)=T(n-1)+O(1) | O(n) |
| T(n)=2T(n/2)+O(n) | O(n log n) |