计算递归算法的时间复杂度需要结合递归结构和子问题规模,通常有以下几种方法:
一、递推方程法(最常用)
步骤:
- 定义T(n):表示问题规模为n时的时间复杂度。
- 拆分递归过程:分析每次递归调用的子问题规模和操作次数。
- 建立递推方程:将T(n)表示为子问题的时间复杂度之和。
- 求解方程:通过代入法、递归树或Master定理得出结果。
示例1:阶乘递归
def factorial(n):
if n <= 1: # 基本情况:O(1)
return 1
return n * factorial(n-1) # 递归调用n-1,每次乘法O(1)
分析:
- 递推方程:T(n) = T(n-1) + O(1)
- 展开:T(n) = T(n-1) + 1 = T(n-2) + 2 = … = T(1) + n-1
- 结果:T(n) = O(n)
示例2:斐波那契数列(朴素递归)
def fib(n):
if n <= 1: # 基本情况:O(1)
return n
return fib(n-1) + fib(n-2) # 递归调用两个子问题
分析:
- 递推方程:T(n) = T(n-1) + T(n-2) + O(1)
- 展开:递归树的节点数呈指数级增长(每个节点分裂为2个子节点)
- 结果:T(n) = O(2ⁿ)
二、递归树法(直观理解)
步骤:
- 画出递归树:每个节点表示一个子问题,标注其规模和操作次数。
- 计算每层的时间复杂度:将每层所有节点的操作次数相加。
- 累加所有层的复杂度:得到总时间复杂度。
示例3:归并排序
def merge_sort(arr):
if len(arr) <= 1: # 基本情况:O(1)
return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid]) # 左半部分:T(n/2)
right = merge_sort(arr[mid:]) # 右半部分:T(n/2)
return merge(left, right) # 合并:O(n)
分析:
- 递推方程:T(n) = 2T(n/2) + O(n)
- 递归树:
- 深度:每次递归规模减半,树高为log n层。
- 每层操作次数:每层总操作次数为O(n)(合并操作)。
- 总复杂度:O(n) × log n层 = O(n log n)
三、Master定理(快速求解)
适用条件:递归方程形如 T(n) = a·T(n/b) + f(n),其中:
- a ≥ 1:子问题的数量
- b > 1:每个子问题的规模缩小因子
- f(n):分解和合并子问题的时间复杂度
结论:
- 若f(n) < n^(log_b(a)),则T(n) = O(n^(log_b(a)))
- 若f(n) = n^(log_b(a)),则T(n) = O(n^(log_b(a)) · log n)
- 若f(n) > n^(log_b(a)),则T(n) = O(f(n))
示例4:二分查找
def binary_search(arr, target, low, high):
if low > high: # 基本情况:O(1)
return -1
mid = (low + high) // 2
if arr[mid] == target: # 找到目标:O(1)
return mid
elif arr[mid] > target: # 左半部分:T(n/2)
return binary_search(arr, target, low, mid-1)
else: # 右半部分:T(n/2)
return binary_search(arr, target, mid+1, high)
分析:
- 递推方程:T(n) = T(n/2) + O(1)
- 参数:a=1, b=2, f(n)=O(1)
- 计算:n^(log_b(a)) = n^0 = 1 → f(n) = O(1)
- 结论:情况2 → T(n) = O(log n)
四、特殊情况处理
1. 递归深度与子问题数量的乘积
若每次递归调用产生多个子问题,且递归深度为d,则时间复杂度为 O(子问题数量^d)。
示例:斐波那契数列(朴素递归)的时间复杂度为O(2ⁿ),因为每次递归分裂为2个子问题,深度为n。
2. 带记忆化的递归
通过缓存结果避免重复计算,将指数级复杂度优化为多项式级。
示例:斐波那契数列(记忆化)
memo = {}
def fib(n):
if n <= 1:
return n
if n not in memo:
memo[n] = fib(n-1) + fib(n-2)
return memo[n]
分析:
- 每个n只计算一次,递归树的节点数降为O(n)。
- 时间复杂度:O(n)
3. 递归与循环结合
若递归内部包含循环,需累加每次递归的操作次数。
示例:
def func(n):
if n <= 1:
return 1
for i in range(n):
print(i)
return func(n//2) + func(n//2)
分析:
- 递推方程:T(n) = 2T(n/2) + O(n)
- Master定理:a=2, b=2, f(n)=O(n) → 情况2 → T(n) = O(n log n)
五、总结
递归算法时间复杂度的计算方法:
- 递推方程法:建立方程并求解(最通用)。
- 递归树法:直观分析每层复杂度,适用于分治算法。
- Master定理:快速求解满足特定形式的递推方程。
- 特殊情况:注意记忆化、递归深度与子问题数量的关系。
关键思路:通过拆分递归过程,将问题转化为数学表达式,再用数学方法求解。



4万+

被折叠的 条评论
为什么被折叠?



