演算法題(5)最長公共子串
最長公共子串
問題描述: 給定兩個不為空的字串,求這兩個字串之間最長的公共子串。
思路: 我們藉助動態規劃的思想,利用遞推公式起始向後逐步計算兩個字串的部分最長公共子串,直至得出整體的最大子串。遞推公式如下:
f
(
i
,
j
)
=
{
0
A
[
i
]
≠
B
[
j
]
∩
(
i
=
0
∪
j
=
0
)
1
A
[
i
]
=
B
[
j
]
∩
(
i
=
0
∪
j
=
0
)
0
A
[
i
]
≠
B
[
j
]
f
(
i
−
1
,
j
−
1
)
+
1
A
[
i
]
=
B
[
j
]
f(i,j)=\begin{cases} 0 & \text A[i]\not=B[j]\cap (i=0 \ \cup \ j = 0)\\1 & \text A[i]=B[j]\cap (i=0 \ \cup \ j = 0)\\0 & \text A[i]\not=B[j]\\ f(i-1, j-1) +1 & \text A[i]=B[j] \end{cases}
同levenshtein編輯距離演算法類似,最長公共子串同樣需要填充表格來列舉所有位置的編輯距離,從而找出最大值。下面我們給出實現程式碼:
class solution:
def __init__(self, A, B):
self.A = A
self.B = B
self.Matrix = []
self.lcstring(self.A, self.B)
def lcstring(self, A, B):
lengthA = len(A)
lengthB = len(B)
longest = 0
longestend = []
if lengthA == 0 or lengthB == 0 :
return
for i in range(lengthA):
self.Matrix.append([])
for j in range(lengthB):
if A[i] == B[j] :
if i == 0 or j == 0:
self.Matrix[i].append(1)
else: self.Matrix[i].append(self.Matrix[i-1][j-1]+1)
if self.Matrix[i][j] > longest:
longestend.clear()
longest = self.Matrix[i][j]
longestend.append(i)
continue
if self.Matrix[i][j] == longest:
longestend.append(i)
else: self.Matrix[i].append(0)
print(longest)
for i in longestend:
print(A[i-(longest-1):i+1])
if __name__ == '__main__':
sol = solution("helloworld","loop")
上述程式碼輸出為最長公共子串的長度,以及該長度的所有子串集。執行結果如下:
我們將輸入字串稍作修改(”helloworld“改為“hilloworld”,“loop”改為“iloor”),以測試其能否完全輸出所有子串,輸出結果如下:
輸出結果表明,我們的演算法基本正確,讀者可以嘗試使用。