Python最长公共子串和最长公共子序列的实现

最长公共子串(The Longest Common Substring)

LCS问题就是求两个字符串最长公共子串的问题。解法就是用一个矩阵来记录两个字符串中所有位置的两个字符之间的匹配情况,若是匹配则为1,否则为0。然后求出对角线最长的1的序列,其对应的位置就是最长匹配子串的位置。

[python]  view plain  copy
  1. def find_lcsubstr(s1, s2):   
  2.     m=[[0 for i in range(len(s2)+1)]  for j in range(len(s1)+1)]  #生成0矩阵,为方便后续计算,比字符串长度多了一列  
  3.     mmax=0   #最长匹配的长度  
  4.     p=0  #最长匹配对应在s1中的最后一位  
  5.     for i in range(len(s1)):  
  6.         for j in range(len(s2)):  
  7.             if s1[i]==s2[j]:  
  8.                 m[i+1][j+1]=m[i][j]+1  
  9.                 if m[i+1][j+1]>mmax:  
  10.                     mmax=m[i+1][j+1]  
  11.                     p=i+1  
  12.     return s1[p-mmax:p],mmax   #返回最长子串及其长度  
  13.   
  14. print find_lcsubstr('abcdfg','abdfg')  

运行得到输出:('dfg',3)


最长公共子序列 (The Longest Common Subsequence)

子串要求字符必须是连续的,但是子序列就不是这样。最长公共子序列是一个十分实用的问题,它可以描述两段文字之间的“相似度”,即它们的雷同程度,从而能够用来辨别抄袭。对一段文字进行修改之后,计算改动前后文字的最长公共子序列,将除此子序列外的部分提取出来,这种方法判断修改的部分,往往十分准确。
        解法就是用动态回归的思想,一个矩阵记录两个字符串中匹配情况,若是匹配则为左上方的值加1,否则为左方和上方的最大值。一个矩阵记录转移方向,然后根据转移方向,回溯找到最长子序列。

[python]  view plain  copy
  1. import numpy  
[python]  view plain  copy
  1. def find_lcseque(s1, s2):   
  2.      # 生成字符串长度加1的0矩阵,m用来保存对应位置匹配的结果  
  3.     m = [ [ 0 for x in range(len(s2)+1) ] for y in range(len(s1)+1) ]   
  4.     # d用来记录转移方向  
  5.     d = [ [ None for x in range(len(s2)+1) ] for y in range(len(s1)+1) ]   
  6.   
  7.     for p1 in range(len(s1)):   
  8.         for p2 in range(len(s2)):   
  9.             if s1[p1] == s2[p2]:            #字符匹配成功,则该位置的值为左上方的值加1  
  10.                 m[p1+1][p2+1] = m[p1][p2]+1  
  11.                 d[p1+1][p2+1] = 'ok'            
  12.             elif m[p1+1][p2] > m[p1][p2+1]:  #左值大于上值,则该位置的值为左值,并标记回溯时的方向  
  13.                 m[p1+1][p2+1] = m[p1+1][p2]   
  14.                 d[p1+1][p2+1] = 'left'            
  15.             else:                           #上值大于左值,则该位置的值为上值,并标记方向up  
  16.                 m[p1+1][p2+1] = m[p1][p2+1]     
  17.                 d[p1+1][p2+1] = 'up'           
  18.     (p1, p2) = (len(s1), len(s2))   
  19.     print numpy.array(d)  
  20.     s = []   
  21.     while m[p1][p2]:    #不为None时  
  22.         c = d[p1][p2]  
  23.         if c == 'ok':   #匹配成功,插入该字符,并向左上角找下一个  
  24.             s.append(s1[p1-1])  
  25.             p1-=1  
  26.             p2-=1   
  27.         if c =='left':  #根据标记,向左找下一个  
  28.             p2 -= 1  
  29.         if c == 'up':   #根据标记,向上找下一个  
  30.             p1 -= 1  
  31.     s.reverse()   
  32.     return ''.join(s)   
  33.   
  34. print find_lcseque('abdfg','abcdfg')  

得到输出结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值