python练习 ---求2个字符串的最长公共子串的三种求解方法

求2个字符串的最长公共子串

最长公共子串(LCS,Longest Common Substring)
思考:
s1 = ‘abcdefg’
s2 = ‘defabcd’

方法一: 直接查找

思路:

最长公共子串一定出现在短的那个字符串里,如果用短的字符串中,先从最长字符开始,逐次减一,到长的那一个字符串中进行匹配.如果存在则说明已经找到,程序结束.

优化:

其实只要找到第一轮的公共子串的索引,最长公共子串也是从它开始的,所以以后的轮次都从这些索引位置开始,
可以减少比较的次数。

str1 = 'abcdefgg好好学习denf'
str2 = 'denf好好学习abcd'
import re 
def str_int(s1,s2):
    if len(s1) > len(s2):
        s1,s2 = s2,s1
        print(s1,s2)
    length = len(s1)
    result = []
    for step in range(length,0 ,-1):
        for start in range(0,length-step+1):
            flag = True
            tmp = s1[start:start+step]
            if s2.find(tmp)>-1 :# 第一次找到,后面要接着找 
                result.append(tmp)
                flag = True
                newstart = start+1
                newstep = step
                while flag:   # 已经找到最长子串,接下来就是判断后面是否还有相同长度的字符串 
                    if newstart+ step >length:  # 大于字符串总长了,退出循环
                        break
                    newtmp = s1[newstart:newstart+newstep] 
                    if s2.find(newtmp)>-1:
                        result.append(newtmp)
                        newstart+=1
                        flag = True
                    else:
                        newstart +=1
                        flag = True    
                return result
            else:
                continue
str_int(str1,str2)

方法二动态规划方法:

通过构建一个矩阵,将两个字符串对应比较,如果相同则为1,不同则为0 ,最后只要是1的下一个还是1 ,那么就可以得到最长的字符串 .

矩阵

如图所示,将得到的每一个1 都与前一个对应的值进行相加,这样在最后就可以知道相同值出现的总个数

s1 = 'abcdenfggdg'  # 构建矩阵列
s2 = 'denfabcd'               # 短的字符串构建矩阵行
def findint(s1,s2):
    if len(s2)>len(s1):   # 交换长短字符串,
        s1,s2= s2,s1
    len1 = len(s1)
    len2 = len(s2)
    xmax = 0
    xindex = 0
    # matrix = [[0 for i in range(len1)] for j in range(len2)]
    matrix = [[0]*len1 for i in range(len2)]
    for i,x in enumerate(s2):# 行
        for j ,y in enumerate(s1):  #列 
            if x==y:  # 如果值相等
#                 matrix2[i][j]=1
                if i==0 or j ==0:       # 位于矩阵的边缘
                    matrix[i][j]=1     # 先如果相等,且又在边缘,那么就设置值为1 
                else:
                    matrix[i][j] = matrix[i-1][j-1]+1   # 否则就由该位置的值的对角线加上一个1 
                if matrix[i][j]> xmax:  # 记录最大值
                    xmax = matrix[i][j]  # 替换最大值
                    xindex = j  # 记录最大值所以
    print(s1[xindex-xmax+1:xindex+1])
    return matrix
print(*findint(s1,s2),sep='\n')
findint(s1,s2)

上面的代码有什么不足么?

通过几个测试便可以发现,当待测字符中存在多个相同最长字符,那么得出的结果会是最后一个最大公共子串.有待优化.
方法三:变形

def getNumofCommonSubstr(str1, str2):
  
    lstr1 = len(str1)
    lstr2 = len(str2)
    record = [[0 for i in range(lstr2+1)] for j in range(lstr1+1)]
    #开辟列表空间 为什么要多一位呢?主要是不多一位的话,会存在边界问题
    # 多了一位以后就不存在超界问题
    maxNum = 0   # 最长匹配长度
    p = 0    # 匹配的起始位
  
    for i in range(lstr1):
        for j in range(lstr2):
            if str1[i] == str2[j]:
    # 相同则累加
                record[i+1][j+1] = record[i][j] + 1
                if record[i+1][j+1] > maxNum:
     # 获取最大匹配长度
                     maxNum = record[i+1][j+1]
     # 记录最大匹配长度的终止位置
                     p = i + 1
    return str1[p-maxNum:p], maxNum
  
  
str1='acbcbced'
str2='acbcbcefa'

res = getNumofCommonSubstr(str1, str2)
print(res)

你可能感兴趣的:(Python练习题)