Python程序员面试算法宝典---解题总结: 第5章 字符串 5.2 如何求两个字符串的最长公共子串

# -*- coding: utf-8 -*-

'''
Python程序员面试算法宝典---解题总结: 第5章 字符串 5.2 如何求两个字符串的最长公共子串

题目:
找出两个字符串的最长公共子串,例如字符串"abccade"与字符串
"dgcadde"的最长公共子串为"cad"

分析:
最长公共子串是动态规划。
假设字符串A与字符串B的长度分别为len1, len2
那么设定一个数组f[i][j],
f[i][j]表示以A[i]与B[j]结尾的字符的这两个字符串的最长公共子串的长度
那么有如下公式:
f[i][j] = { f[i-1][j-1] + 1, if A[i] == B[j]
         {  max{ f[i-1][j], f[i][j-1] } , else
初始值:
令f[][]中的元素全部初始化为0
目标:
f[len1-1][len2-1]
关键:
1 书上解法
i和j的取值是通过双重遍历确认的
而不是通过str1[i]是否等于str2[j]确认
自顶向下递推
而且因为需要找到该字符串,因此需要填表,
然后根据填表的结果往回递推。
注意:
str1[i] != str2[j]就需要设置
f[i][j] = 0,
而f[i][j] = max{f[i-1][j], f[i][j-1]}
是求最长递增子序列,不是求最长公共字符串的

2
str[-3:] #截取倒数第三位到结尾

3 之所以没想到
是因为忘记最长公共字符串的递推方法
i和j的下标是通过双层循环确定的
参考:
Python程序员面试算法宝典
'''

def lcs(str1, str2):
    if not str1 or not str2:
        return ""
    len1 = len(str1)
    len2 = len(str2)
    f = [[0] * len1 for i in range(len2)]
    # 设置边值
    maxValue = 0
    maxRow = 0
    maxCol = 0
    for i in range(len1):
        f[i][0] = 0 if str1[i] != str2[0] else 1
    for j in range(len2):
        f[0][j] = 0 if str1[0] != str2[j] else 1

    for i in range(1, len1):
        for j in range(1, len2):
            if str1[i] == str2[j]:
                f[i][j] = f[i-1][j-1] + 1
                if maxValue < f[i][j]:
                    maxValue = f[i][j]
                    maxRow = i
                    maxCol = j
            else:
                # 两个值不等,那么值为0
                f[i][j] = 0
    # 往回递推
    string = str1[: maxRow + 1]
    result = string[-maxValue:]
    return result


def process():
    str1 = "abccade"
    str2 = "dgcadde"
    result = lcs(str1, str2)
    print result



if __name__ == "__main__":
    process()

猜你喜欢

转载自blog.csdn.net/qingyuanluofeng/article/details/94298998