求任意两字符串的最长公共子序列长度,并找出所有最长公共子序列

一、代码

def lcs(string1, string2):
    len1 = len(string1)
    len2 = len(string2)
    # dp[i][j]表示string1前i位子串与string2前j位子串的最长公共子序列的长度
    dp = [[0 for j in range(len2 + 1)] for i in range(len1 + 1)]
    for i in range(1, len1 + 1):
        for j in range(1, len2 + 1):
            if string1[i - 1] == string2[j - 1]:
                dp[i][j] = dp[i - 1][j - 1] + 1
            else:
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
    # 返回dp数组和最长公共子序列的长度
    return dp, dp[len1][len2]


def get_all_lcs(string1, string2, dp, i, j, dest_set, cs):
    """
    根据dp逆推出所有string1和string2的最长公共子序列
    :param string1:
    :param string2:
    :param dp: lcs(string1, string2) 返回的dp数组
    :param i: 从string1的第i位逆推
    :param j: 从string2的第j位逆推
    :param dest_set: 保存所有最长公共子序列的set
    :param cs: 当前逆推阶段的公共子序列
    :return:
    """
    # 逆推完毕
    if dp[i][j] == 0:
        dest_set.add(cs)
        return
    # 若当前逆推阶段两字符相等
    if string1[i - 1] == string2[j - 1]:
        cs = string1[i - 1] + cs
        get_all_lcs(string1, string2, dp, i - 1, j - 1, dest_set, cs)
    # 若两字符不等,需要选择正确逆推路径
    # 由于lcs中,两字符不相等时dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
    # 应当选择dp[i - 1][j], dp[i][j - 1]中较大的那个最为逆推路径
    # 若dp[i - 1][j], dp[i][j - 1]相等,则分别逆推两条路径
    else:
        if dp[i][j - 1] > dp[i - 1][j]:
            get_all_lcs(string1, string2, dp, i, j - 1, dest_set, cs)
        elif dp[i][j - 1] < dp[i - 1][j]:
            get_all_lcs(string1, string2, dp, i - 1, j, dest_set, cs)
        else:
            get_all_lcs(string1, string2, dp, i, j - 1, dest_set, cs)
            get_all_lcs(string1, string2, dp, i - 1, j, dest_set, cs)


s1 = "12377861542"
s2 = "65435782"
dp, max_len = lcs(s1, s2)
print(max_len)

all_lcs = set()
get_all_lcs(s1, s2, dp, len(s1), len(s2), all_lcs, "")
print(all_lcs)

2、运行结果

4
{'6542', '3782'}

你可能感兴趣的:(求任意两字符串的最长公共子序列长度,并找出所有最长公共子序列)