动态编程方法之函数的记忆化-Memoization
动态规划是一种解决复杂问题的算法思想,它主要是利用历史信息来避免重复计算,从而提高算法的效率。在动态规划算法中,函数的记忆化是一种重要的技巧,它是指将函数的计算结果都存储在一个字典或数组中,在下一次调用时直接返回这个存储的结果,从而避免重新计算。本文将介绍函数的记忆化在动态规划算法中的应用。
一、什么是函数的记忆化?
函数的记忆化指的是将函数的计算结果缓存起来,在下一次需要计算时直接返回缓存中的结果,避免重新计算。这种技术能够很好地提高代码的性能,特别是在需要多次调用函数时更为明显。
下面是一个简单的例子,演示了如何使用函数的记忆化技术:
def fib(n, cache = {}):
if n == 1 or n == 2:
return 1
if n in cache:
return cache[n]
else:
cache[n] = fib(n-1, cache) + fib(n-2, cache)
return cache[n]
print(fib(20))
这段代码中的函数 fib 的作用是计算斐波那契数列的第 n 项。在实现时,我们定义了一个缓存 cache,用于记录每个 n 的计算结果,从而实现快速返回。在计算 fib(20) 时,需要递归计算 fib(19) 和 fib(18) 两个值,这两个函数的计算结果都存储在缓存中,并在后续递归中直接返回,从而避免了重复计算。
二、函数的记忆化在动态规划中的应用
函数的记忆化技术在动态规划算法中得到了广泛应用,在以下场景中特别常见:
1、递归方程中存在重复计算的情况
动态规划算法是一种基于递归的算法,如果递归方程中存在重复计算的情况,那么就可以使用函数的记忆化技术来避免重复计算。这种方法可以大大减少运行时间。
例如,假设要计算斐波那契数列的第 n 项,可以使用递归算法,但是这种算法的时间复杂度为 O(2^n),非常低效。可以使用函数的记忆化来避免重复计算的问题,时间复杂度可以降到 O(n):
def fib(n, memo = {}):
if n == 0 or n == 1:
return n
if n in memo:
return memo[n]
memo[n] = fib(n-1, memo) + fib(n-2, memo)
return memo[n]
print(fib(20))
2、需要反复调用函数的情况
如果需要反复调用一个函数,并且函数的计算结果只与输入参数有关,那么可以使用函数的记忆化来记录这个函数的计算结果,从而避免重复计算,提高执行效率。
例如,假设需要计算一个长字符串的所有子串中出现次数最多的字符,可以使用函数的记忆化来记录每个子串的计算结果,从而减少重复计算的情况:
def max_char(s, memo = {}):
if len(s) == 0:
return None
if len(s) == 1:
return s[0]
if s in memo:
return memo[s]
max_count, max_char = 0, None
for c in set(s):
count = s.count(c)
if count > max_count:
max_count, max_char = count, c
memo[s] = max_char
return max_char
s = 'abcabbabcabbabbcabcabc'
print(max_char(s))
在这段代码中,函数 max_char 的作用是计算字符串 s 所有的子串中出现次数最多的字符。在实现时,使用函数的记忆化技术,记录每个子串的计算结果,从而避免重复计算。
三、结语
函数的记忆化是一种非常有用的技术,在动态规划算法中得到了广泛应用。通过缓存函数的计算结果,可以大大减少代码的执行时间,提高程序的性能。需要注意的是,在使用函数的记忆化时,一定要注意缓存的存储和清空,避免出现存储空间过大的问题。
