返回
从缓存到表:动态规划的简单入门
后端
2024-02-05 11:40:49
从缓存到表:动态规划的简单入门
引论:算法与效率
在计算机科学领域,算法扮演着至关重要的角色。它是一系列步骤的集合,用于解决特定问题。算法的效率尤为关键,因为它决定了问题的求解时间和资源消耗。为了提升算法的效率,我们引入了一种名为“动态规划”的技术。
动态规划的初识:建立缓存表
动态规划的基本思想在于将问题的子问题结果存储在缓存表中,以便在需要时直接查表,避免重复计算。这种方法可以大大提高算法的效率。
案例一:斐波那契数列
斐波那契数列是一个经典的数学问题。它的定义如下:
F(0) = 0
F(1) = 1
F(n) = F(n-1) + F(n-2) (n ≥ 2)
若使用递归的方式来求解斐波那契数列,时间复杂度为指数级,非常低效。而采用动态规划的方法,则只需存储已经计算过的子问题结果,当再次遇到相同子问题时,直接查表即可。如此一来,时间复杂度将降至线性级别。
def fib(n, memo):
"""计算斐波那契数列的第n项。
Args:
n: 要计算的项数。
memo: 一个缓存表,存储已经计算过的子问题结果。
Returns:
斐波那契数列的第n项。
"""
# 检查是否存在缓存结果
if n in memo:
return memo[n]
# 计算第n项并存储在缓存表中
if n <= 1:
result = n
else:
result = fib(n-1, memo) + fib(n-2, memo)
memo[n] = result
return result
def main():
# 创建缓存表
memo = {}
# 计算并输出斐波那契数列的前10项
for n in range(10):
print(f"F({n}) = {fib(n, memo)}")
if __name__ == "__main__":
main()
输出:
F(0) = 0
F(1) = 1
F(2) = 1
F(3) = 2
F(4) = 3
F(5) = 5
F(6) = 8
F(7) = 13
F(8) = 21
F(9) = 34
案例二:最长公共子序列
最长公共子序列(Longest Common Subsequence,LCS)问题是指,给定两个字符串,求出它们的共同子序列中长度最长的一个。
def lcs(s1, s2, memo):
"""计算两个字符串的最长公共子序列的长度。
Args:
s1: 第一个字符串。
s2: 第二个字符串。
memo: 一个缓存表,存储已经计算过的子问题结果。
Returns:
两个字符串的最长公共子序列的长度。
"""
# 检查是否存在缓存结果
key = (s1, s2)
if key in memo:
return memo[key]
# 计算最长公共子序列的长度并存储在缓存表中
if not s1 or not s2:
result = 0
elif s1[-1] == s2[-1]:
result = lcs(s1[:-1], s2[:-1], memo) + 1
else:
result = max(lcs(s1[:-1], s2, memo), lcs(s1, s2[:-1], memo))
memo[key] = result
return result
def main():
# 创建缓存表
memo = {}
# 计算并输出两个字符串的最长公共子序列的长度
s1 = "ABCDGH"
s2 = "AEDFHR"
print(f"LCS({s1}, {s2}) = {lcs(s1, s2, memo)}")
if __name__ == "__main__":
main()
输出:
LCS(ABCDGH, AEDFHR) = 3
结语:动态规划的强大力量
通过以上两个案例,我们了解了动态规划的基本思想和应用方法。动态规划的强大之处在于,它可以将一个复杂问题分解成更小的子问题,并通过存储子问题的结果来避免重复计算。这使得动态规划算法的时间复杂度大大降低,从而提高了算法的效率。