LCS(最长公共子串) python3实现

	LCS问题就是求两个字符串最大相同的公共子串;我们现假设有两个字符串X,Y。其长度分别为m,n
	我们从X,Y两个字符串的最后一个字符串开始看起
	如果  Xm = Yn:
	LCS(X, Y) = LCS(Xm-1, Yn-1)+ "Xm"
	如果Xm != Yn:
	LCS(X,Y) = max(LCS(Xm-1,Yn), LCS(Xm, Yn-1))
	我们即构建了这样的动态转移方程。如果还不是特别明白,我们来看以下例子。
LCS(最长公共子串) python3实现_第1张图片
	有了上述的动态转移方程,我们该如何编写代码呢?
	我们采用递归加备忘录的方式,基于刚刚的动态转移方程我们设置一个二维数组用来
	存放当前最长的公共子串。我们可得到以下递推式。

| LCS(最长公共子串) python3实现_第2张图片

				对于下列两个字符串,其产生的二维数组如下。
xi A B A B A C A B
yi 0 0 0 0 0 0 0 0 0
A 0 1 1 1 1 1 1 1 1
A 0 1 1 2 2 2 2 2 2
C 0 1 1 2 2 2 3 3 3
	因此,我们只需对该二维数组进行遍历即能得到一个结果,若有多个,
	需要对该二维数组进行深度优先遍历。我们这里只考虑一种情况。
	从两个字符串最后一个字符开始看起,
	如果相等的话,则它的值来至与他在该数组的左上方,否则则来自它的左方或上方
	具体代码实现如下:
def max_common_s(s1, s2):
    chart = [[0 for i in range(len(s1)+1)]for j in range(len(s2)+1)]            #建立一个二维数组
    for i in range(1, len(s2)+1):
        for j in range(1, len(s1)+1):       
            if s1[j-1] == s2[i-1]:                                          #如果对应的两个值相等,则其左上方的值加1
                chart[i][j] = chart[i-1][j-1]+1
            else:
                chart[i][j] = max(chart[i-1][j], chart[i][j-1])             #要是不相等,则取其右方或上方的最大值
    return chart

def find_one(chart, s1, s2):
    max_str = ''
    i = len(s1)
    j = len(s2)
    while i > 0 and j > 0:
        if s1[i-1] == s2[j-1]:                  #若最后一个字符相等,则一定来自于左上方
            max_str += s1[i-1]
            i -= 1
            j -= 1
        else:
            if chart[j][i-1] > chart[j-1][i]:           #若左边的数字较大,则来自左边
                i -= 1
            else:                                       #否则来自上方
                j -= 1
    return reversed(max_str)                            #逆序输出


if __name__ == '__main__':
    s1 = 'ABCasdasd'
    s2 = 'ADCsadsadsad'
    chart = max_common_s(s1, s2)
    print(''.join(list(find_one(chart, s1, s2))))
	关于此问题,还可扩展到编辑距离问题。大家可以尝试用该方法解决

你可能感兴趣的:(算法)