python 动态规划总结(待补充。。。。。。)

动态规划总结

  • 1. 分治法和动态规划的区别
  • 2. 什么问题适合使用动态规划解决
  • 2. 动态规划通常会包含两个环节:
    • 1. 递归:求解子问题。
    • 2. 记忆化:把已经计算出的结果保存起来。
  • 3. 题目应用:
    • 输入两个字符串,求最长公共子序列(LCS,Longest Common Subsequence)的长度。

大部分内容和例子均来自 骆昊老师知乎文章 : 透过面试说算法(4) - 动态规划

1. 分治法和动态规划的区别

动态规划和之前文章中讲到的分治法的区别。分治法要解决的子问题是相互独立的,可以分别进行求解;而动态规划要解决的子问题是有重叠的,所以可以通过记忆化技术把已解决问题的结果保存起来。使用动态规划可以让很多问题的时间复杂度从指数级降到 O ( N 3 ) O(N^3) O(N3) O ( N 2 ) O(N^2) O(N2) 甚至是 O ( N ) O(N) O(N)

2. 什么问题适合使用动态规划解决

如果想知道一个问题适不适合用动态规划来解决,可以看看问题是否符合以下两条性质:

具备最优子结构:整个问题的最佳解法可以由各个子问题的最佳解法构成。

具备相互重叠子问题:子问题会反复出现。

2. 动态规划通常会包含两个环节:

1. 递归:求解子问题。

我的Python 递归总结

2. 记忆化:把已经计算出的结果保存起来。

3. 题目应用:

输入两个字符串,求最长公共子序列(LCS,Longest Common Subsequence)的长度。

题目参考理解1
题目参考理解2

公式:
python 动态规划总结(待补充。。。。。。)_第1张图片

def lcs_n(a,b):
    if a == '' or b == '':
        return 0
    if a[0] == b[0]:
        return lcs_n(a[1:],b[1:])+1
    else:
        one = lcs_n(a[1:],b)
        two = lcs_n(a,b[1:])
        return max(one,two)

验证:

a = 'BDCABA'
b = 'ABCBDAB'

res = lcs_n(a,b)
print(res)

虽然问题解决,但是时间复杂度特别高,其渐近时间复杂度为 ( 2 M + 2 N ) (2^M+2^N) (2M+2N) 。可能大家已经注意到了,上面的算法再计算公共子序列长度时存在大量的重复运算,跟斐波那契数列优化前的代码是一样的。既然如此我们就可以考虑用动态规划的思路,通过保存中间运算结果对代码加以优化。

def lcs(a, b):
    matrix = [[0] * (len(b) + 1) for _ in range(len(a) + 1)]
    for i in range(1, len(a) + 1):
        for j in range(1, len(b) + 1):
            if a[i - 1] == b[j - 1]:
                matrix[i][j] = matrix[i - 1][j - 1] + 1
            else:
                matrix[i][j] = max(matrix[i - 1][j], matrix[i][j - 1])
    return matrix[-1][-1]

上面算法的渐近时间复杂度为 $ O( M * N)$,也可以利用functools里的装饰器lru_cache 添加记忆

import functools
@functools.lru_cache(maxsize=None)

def lcs_n(a,b):
    if a == '' or b == '':
        return 0
    if a[0] == b[0]:
        return lcs_n(a[1:],b[1:])+1
    else:
        one = lcs_n(a[1:],b)
        two = lcs_n(a,b[1:])
        return max(one,two)

a = 'BDCABA'
b = 'ABCBDAB'

res = lcs_n(a,b)
print(res) # 4

你可能感兴趣的:(python小技巧,leetcode,python,动态规划,数据结构,算法)