时间复杂度 是算法面试中必问的核心考点,也是评判代码优劣的核心指标。但很多开发者对时间复杂度的理解停留在“背答案”阶段,遇到递归、嵌套循环等复杂场景就无从下手。本文将以 四大核心公式 和 五类代码模板 为框架,带你彻底掌握时间复杂度分析的本质逻辑,从此告别“玄学”猜想!
对于算法时间函数 ( T(n) ),存在常数 ( C ) 和 ( n_0 ),使得当 ( n > n_0 ) 时:
[ T(n) \leq C \cdot f(n) ]
则记作 ( T(n) = O(f(n)) )。
代码模板:
for i in range(n):
# O(1)的操作
时间复杂度:
[ O(n) ]
变体案例:
i = 1
while i < n:
i *= 2 # 循环次数为 log₂n → O(log n)
代码模板:
for i in range(n):
for j in range(n):
# O(1)的操作
时间复杂度:
[ O(n \times n) = O(n^2) ]
特殊场景:
for i in range(n):
for j in range(i, n):
# 内层循环次数 = n - i
# 总次数 = Σ(n - i) = n(n-1)/2 → O(n²)
代码模板(二分查找):
def recur(n):
if n <= 1: return
recur(n/2) # 递归调用规模减半
recur(n/2)
递推关系:
[ T(n) = 2T(n/2) + O(1) ]
用主定理(Master Theorem)求解:
[ a=2, b=2, d=0 → T(n) = O(n^{\log_2 2}) = O(n) ]
典型场景:动态数组(如Python List)的扩容
left = 0
right = len(nums) - 1
while left < right:
# O(1)的操作
left += 1
right -= 1
分析:循环次数为 n/2 → 去掉常数项 → O(n)
def dfs(node):
if not node: return
dfs(node.left)
dfs(node.right)
递推公式:
[ T(n) = 2T(n/2) + O(1) ]
主定理求解:a=2, b=2 → O(n)
递推关系:
[ T(n) = T(k) + T(n-k-1) + O(n) ]
递推公式:
[ T(n) = 2T(n/2) + O(n) ]
主定理求解:a=2, b=2, d=1 → O(n log n)
dp = [0]*(n+1)
for i in range(1, n+1):
for j in range(1, i):
dp[i] = max(dp[i], dp[j] + ...)
分析:外层循环n次,内层平均n/2次 → O(n²)
错误认知:O(n)
实际分析:
递归树有 ( 2^0 + 2^1 + … + 2^{n-1} = 2^n -1 ) 个节点 → O(2ⁿ)
find操作:单次最差O(log n),但经过路径压缩后,m次操作的均摊成本为
[ O(\alpha(n)) ] (α为阿克曼函数的反函数,接近常数)
代码模式 | 时间复杂度 | 典型案例 |
---|---|---|
单层循环 | O(n) | 遍历数组 |
双层嵌套循环 | O(n²) | 冒泡排序 |
分治递归(子问题减半) | O(n log n) | 归并排序 |
指数级递归 | O(2ⁿ) | 暴力搜索 |
对数级循环 | O(log n) | 二分查找 |
“该算法的时间复杂度是 O(…) ,因为核心部分采用了…结构,根据…公式可推导出…”
本文的LeetCode练习题:
掌握这套分析方法后,95%的时间复杂度问题都可快速推导。建议在刷题时先自行分析复杂度,再与题解对比验证。如果有其他复杂场景的疑问,欢迎在评论区交流!