fibonacci的4种实现
文章目录
- 工具函数
- 1. base递归
- 2. 数组缓存计算结果
- 3. 自底向上迭代替换递归
- 4. 终极解法,根据状态推导式 f(n) = f(n-1) + f(n-2) 只保留要前两个状态
fibonacci的4种实现.把n=0也考虑在内
工具函数
计算运行时间与内存
def time_memory(func):@functools.wraps(func)def wrapper(*args, **kwargs):tracemalloc.start()start = time.perf_counter()res = func(*args, **kwargs)duration = (time.perf_counter() - start)*1000current, peak = tracemalloc.get_traced_memory()tracemalloc.stop()print(f"{func.__name__} excution duration: {duration:.3f} ms")print(f"{func.__name__} memory usage: current = {current / 1024:.3f} KB, peak = {peak / 1024:.3f} KB")return resreturn wrapper
1. base递归
最简单的递归实现,此种实现分线下来会有非常多重复子问题计算,导致时间复杂度为O(2^n)指数级别.
def fibonacci_base(n: int):if n < 0:raise ValueError(f'{n} is invalid')elif n == 0:return 0elif n == 1:return 1else:return fibonacci_base(n-1) + fibonacci_base(n-2)
测试样例
@time_memory
def test_base(n: int):res = fibonacci_base(n)print(res)test_base(18)
运行结果
test_base excution duration: 3.812 ms
2. 数组缓存计算结果
考虑到base解法有不少重复计算的数值,可以用一个数组存放已经计算好的数值,递归计算时可以查看数组里面是否有之前已经计算好的值,使用空间换时间的方法,算法时间复杂度O(N) 空间复杂度O(N)
def do_fibonacci_e1(n: int, buffer: list[int]):if n < 0:raise ValueError(f'{n} is invalid')if n == 0:return buffer[0]elif n == 1:if buffer[1] == 0:buffer[1] = 1return buffer[1]else:if buffer[n] == 0:buffer[n] = do_fibonacci_e1(n-1, buffer) + do_fibonacci_e1(n-2, buffer)return buffer[n]def fibonacci_e1(n: int):if n < 0:raise ValueError(f'{n} is invalid')else:buffer = [0] * (n+1)return do_fibonacci_e1(n, buffer)
测试样例
@time_memory
def test_e1(n: int):res = fibonacci_e1(n)print(res)test_e1(18)
运行结果
test_e1 excution duration: 0.097 m
3. 自底向上迭代替换递归
自底向上的解决办法,使用循环替代递归,时间复杂度O(N) 空间复杂度O(N) 循环实现消耗资源更少,所以时间更快.
代码:
def fibonacci_e2(n: int):if n < 0:raise ValueError(f'{n} is invalid')elif n == 1:return 1# n >= 2 开始构建数组dp = [0]*(n+1)dp[0] = 0dp[1] = 1for i in range(2, n+1):dp[i] = dp[i-1] + dp[i-2]return dp[n]
测试样例
@time_memory
def test_e2(n: int):res = fibonacci_e2(n)print(res)test_e2(18)
运行结果
test_e2 excution duration: 0.052 ms
4. 终极解法,根据状态推导式 f(n) = f(n-1) + f(n-2) 只保留要前两个状态
进一步将时间复杂度降低到O(1)
def fibonacci_e3(n: int):if n < 0:raise ValueError(f'{n} is invalid')elif n == 1:return 1pre = 0curr = 1for i in range(2, n+1):res = pre + currpre = currcurr = resreturn res
测试样例
@time_memory
def test_e3(n: int):res = fibonacci_e3(n)print(res)
运行结果
test_e3 excution duration: 0.040 ms