时间复杂度和空间复杂度计算
因为是非科班转码,所以有很多基础概念不是很熟悉,因此想每天学着写技术博客~
时间复杂度
时间复杂度描述的是:算法运行时间随输入规模增长的变化趋势,不是具体执行了多少秒,而是“操作次数”的增长速度。
- 用 大 O 表示法(Big O notation),比如 O(1)、O(n)、O(log n)、O(n²) 等。
- 只关注最坏情况(worst-case)和主导项(忽略常数和低阶项)。
- 假设每条基本语句(如赋值、比较、加减)执行时间为常数。
📌 常见时间复杂度(从小到大)
| 复杂度 | 名称 | 示例 |
|---|---|---|
| O(1) | 常数时间 | return arr[0] |
| O(log n) | 对数时间 | 二分查找 |
| O(n) | 线性时间 | 遍历数组一次 |
| O(n log n) | 线性对数 | 快速排序、归并排序 |
| O(n²) | 平方时间 | 两层嵌套循环 |
| O(2ⁿ) | 指数时间 | 递归求斐波那契(无记忆化) |
| O(n!) | 阶乘时间 | 全排列暴力解 |
🔍 如何分析时间复杂度?——实战技巧
1. 单层循环
python
编辑
for i in range(n):
print(i)
→ 执行 n 次 → O(n)
2. 嵌套循环
python
编辑
for i in range(n):
for j in range(n):
print(i, j)
→ 外层 n 次,内层每次 n 次 → n × n = n² → O(n²)
3. 循环变量倍增/减半
python
编辑
i = 1
while i < n:
i *= 2
→ i 取值:1, 2, 4, 8, ..., 直到 ≥n
→ 循环次数 ≈ log₂n → O(log n)
4. 递归函数
python
编辑
def fib(n):
if n <= 1: return n
return fib(n-1) + fib(n-2)
→ 每次调用产生两个分支,深度为 n → 调用次数 ≈ 2ⁿ → O(2ⁿ)
但如果加了记忆化(缓存),就变成 O(n) 。
5. 多个独立部分
python
编辑
for i in range(n): ... # O(n)
for i in range(n): ... # O(n)
→ 总时间 = O(n) + O(n) = O(2n) → 忽略常数 → O(n)
空间复杂度
空间复杂度描述的是:算法在运行过程中临时占用存储空间的大小随输入规模的增长趋势。
✅ 关键点:
- 包括变量、数组、递归栈等额外空间。
- 不包括输入数据本身占用的空间(除非你复制了它)。
- 同样用大 O 表示。
📌 常见空间复杂度分析
1. 常数空间
python
编辑
def add(a, b):
return a + b
→ 只用几个变量 → O(1)
2. 使用额外数组
python
编辑
def double(arr):
res = []
for x in arr:
res.append(2 * x)
return res
→ 创建了长度为 n 的新数组 → O(n)
3. 递归调用栈
python
编辑
def factorial(n):
if n == 0: return 1
return n * factorial(n-1)
→ 递归深度为 n → 调用栈有 n 层 → O(n)
4. 原地操作 vs 非原地
- 原地反转数组(只用几个指针)→ O(1) 空间
- 用新数组存结果 → O(n) 空间
三、经典例子对比
| 算法 | 时间复杂度 | 空间复杂度 | 说明 |
|---|---|---|---|
| 冒泡排序 | O(n²) | O(1) | 原地排序 |
| 归并排序 | O(n log n) | O(n) | 需要临时数组 |
| 哈希表查重 | O(n) | O(n) | 用 set 存元素 |
| 二分查找(数组) | O(log n) | O(1) | 无需额外空间 |
| DFS(递归遍历树) | O(n) | O(h) | h 是树高,最坏 O(n) |
| 动态规划(一维数组) | O(n) | O(n) 或 O(1) | 可滚动数组优化 |