动态规划专题

最大子数组

这个题,初学之时,老师教我们用分治算法,分三路:在左边子数组、在右边子数组以及跨越中线,其实用动态规划已经很简单了,看状态转移方程就明白了:

[dp[i] = egin{cases}arr[i], & quad i==0\ max{dp[i-1]+arr[i], arr[i]}, & quad otherwise end{cases} ]

def maximum_subarr(arr):
    if not arr:
        return None
    dp = [0]*len(arr)
    dp[0] = arr[0]
    for i in range(1, len(arr)):
        dp[i] = max(dp[i-1]+arr[i], arr[i])
    return max(dp)

编辑距离

状态转移方程为:

[dp[i][j] = egin{cases}dp[i-1][j-1], & quad s1[i] == s2[j]\ min{dp[i-1][j], dp[i][j-1], dp[i-1][j-1]}+1, & quad otherwise end{cases} ]

注意边界的情况:i、j是从1开始的,0表示空字符串。

def edit_distance(s1, s2):
    if len(s1) == 0:
        return len(s2)
    if len(s2) == 0:
        return len(s1)

    dp = [[0]*(len(s2) + 1) for _ in range(len(s1) + 1)]
    for i in range(len(s1)+1):
        for j in range(len(s2)+1):
            if i == 0:
                dp[i][j] = j
            elif j == 0:
                dp[i][j] = i
            else:
                if s1[i-1] == s2[j-1]:
                    dp[i][j] = dp[i-1][j-1]
                else:
                    dp[i][j] = min(min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1]) + 1

    return dp[len(s1)][len(s2)]

最长公共子串

状态转移方程为:

[dp[i][j] = egin{cases}dp[i-1][j-1]+1, & quad s1[i] == s2[j]\ 0, & quad otherwise end{cases} ]

最终的答案是整个dp数组中的最大值。

def longest_common_substring(s1, s2):
    if not s1 or not s2:
        return 0

    max_len = 0
    dp = [[0]*(len(s2)+1) for _ in range(len(s1)+1)]
    for i in range(1, len(s1)+1):
        for j in range(1, len(s2)+1):
            if s1[i-1] == s2[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
                if dp[i][j] > max_len:
                    max_len = dp[i][j]
            else:
                dp[i][j] = 0

    return max_len

最长公共子序列

子序列可以不是连续的,所以,状态转移方程为:

[dp[i][j] = egin{cases}dp[i-1][j-1]+1, & quad s1[i] == s2[j]\ max{dp[i-1][j], dp[i][j-1]}, & quad otherwise end{cases} ]

def longest_common_subseq(s1, s2):
    if not s1 or not s2:
        return 0
    m = len(s1)
    n = len(s2)
    dp = [[0]*(n+1) for _ in range(m+1)]
    for i in range(1, m+1):
        for j in range(1, n+1):
            if s1[i-1] != s2[j-1]:
                dp[i][j] = max(dp[i-1][j], dp[i][j-1])
            else:
                dp[i][j] = max(max(dp[i-1][j-1]+1, dp[i][j-1]), dp[i-1][j])
    return dp[m][n]
原文地址:https://www.cnblogs.com/YoungF/p/14296961.html