最长公共子串
问题描述:给定两个字符串,找到他们公共的子串,要求连续
b a b
c 0 0 0
a 0 1 0
b 1 0 1
a 0 1 0
矩阵的斜对角线最长的那个就是最长公共子串。
不过在二维矩阵上找最长的由1组成的斜对角线也是件麻烦费时的事,下面改进:当要在矩阵是填1时让它等于其左上角元素加1。
b a b
c 0 0 0
a 0 1 0
b 1 0 2
a 0 2 0
这样矩阵中的最大元素就是 最长公共子串的长度。
在构造这个二维矩阵的过程中由于得出矩阵的某一行后其上一行就没用了,所以实际上在程序中可以用一维数组来代替这个矩阵。
# 最长公共子串
# 解题思路:建立一个二阶矩阵,只需看对角线连续为1 的最长长度,
# 简化之,可以建立一个一维数组,不断更新,值若为1就加上左上角的值
from copy import deepcopy
class Solution:
"""
@param: A: A string
@param: B: A string
@return: the length of the longest common substring.
"""
def longestCommonSubstring(self, A, B):
labelOfLastList = [0 for _ in range(len(A))]
labelOfThisList = [0 for _ in range(len(A))]
maxLength = 0
for b in B:
for i, a in enumerate(A):
if a == b:
labelOfThisList[i] = 1 if i == 0 else labelOfLastList[i - 1] + 1
else:
labelOfThisList[i] = 0
labelOfLastList = deepcopy(labelOfThisList)
maxOfThisList = max(labelOfThisList)
if maxLength < maxOfThisList:
maxLength = maxOfThisList
return maxLength
A = ''
B = ''
X = Solution()
print(X.longestCommonSubstring(A, B))
最长公共子序列
问题描述:给定两个字符串,找到公共的子序列, 不要求连续
解决方法:利用动态规划,先找到最长公共子序列长度,
回溯的方法:
采用一个标记函数Flag[i,j],当
①:C[i,j]=C[i-1,j-1]+1 时 标记Flag[i,j]="left_up"; (左上方箭头)
②:C[i-1,j]>=C[i,j-1] 时 标记Flag[i,j]="left"; (左箭头)
③: C[i-1,j]<C[i,j-1] 时 标记Flag[i,j]="up"; (上箭头)
注:这种方法只能找到一个子序列,实际上子序列有多种存在
# 最长公共子序列
# 和子串的区别在于,子序列不要求连续,也就是说一个长度为N的字符串,可以有2的N次方个子序列
# 解题思路:利用动态规划。
# C[i,j]表示两个字符串的前i个和前j个字符的最长公共子序列长度
# 然后回溯,找到最长公共子序列
def longestCommonSubsequence(A, B):
lenA = len(A)
lenB = len(B)
longestLengthList = [[0 for _ in range(lenA + 1)] for _ in range(lenB + 1)]
flag = [[0 for _ in range(lenA + 1)] for _ in range(lenB + 1)]
for i in range(lenA + 1):
for j in range(lenB + 1):
if i == 0 or j == 0:
longestLengthList[i][j] = 0
elif A[i - 1] == B[j - 1]:
longestLengthList[i][j] = longestLengthList[i - 1][j - 1] + 1
flag[i][j] = 'leftUp'
elif longestLengthList[i][j - 1] >= longestLengthList[i - 1][j]:
longestLengthList[i][j] = longestLengthList[i][j - 1]
flag[i][j] = 'left'
else:
longestLengthList[i][j] = longestLengthList[i - 1][j]
flag[i][j] = 'up'
longestSubsequence = ''
longestLength = max(max(longestLengthList))
i = lenA
j = lenB
while len(longestSubsequence) < longestLength:
if flag[i][j] == 'leftUp':
longestSubsequence += A[i-1]
i -= 1
j -= 1
elif flag[i][j] == 'left':
j -= 1
elif flag[i][j] == 'up':
i -= 1
return longestSubsequence[::-1]
A = 'acgbfhk'
B = 'cegefkh'
print(longestCommonSubsequence(A, B))
参考博客:
http://www.cnblogs.com/zhangchaoyang/articles/2012070.html
http://www.cnblogs.com/huangxincheng/archive/2012/11/11/2764625.html