一、問題描述
給定乙個序列x = ,另乙個序列z = 是x的子串行,如果存在乙個嚴格遞增的x中元素下標的序列,使得xij = zj (1<=j<=k)。
給定兩個序列x和y,當另一串行z既是x的子串行又是y的子串行時,稱z是序列x和y的公共子串行。最長公共子串行就是公共子串行中長度最長的子串行。
接下來簡單明瞭地舉例。x = ,x的子串行就是x序列元素按順序組成的乙個子集,比如 ,等。給定另乙個序列y = ,則就是x、y的乙個子串行,而、則是x、y的最長公共子串行。
二、最優子結構證明
假設序列x = ,序列y = ,序列z = 為序列x和y的某個最長公共子串行。那麼:
①若xm = yn,那麼zk=xm=yn,且zk-1就是xm-1和yn-1的乙個最長公共子串行。
②若xm ≠ yn,且zk ≠ xm,那麼zk就是xm-1和yn的乙個最長公共子串行。
③若xm ≠ yn,且zk ≠ yn,那麼zk就是xm和yn-1的乙個最長公共子串行。
證明:①由已知,假設zk ≠ xm,那麼則可以把xm(yn)放在公共子串行zk的末尾,這樣就形成了乙個新的公共子串行,且這個公共子串行的長度 = 原來的序列z長度 + 1,與假設矛盾,所以 zk=xm=yn。再假設zk-1不是xm-1和yn-1的最長公共子串行,說明存在乙個更長的子串行,這時再把xm(yn)附在這個更長子序列的後面,則得到乙個x和y的更長的公共子串行,它的長度 > 原來的z序列長度,與z是x和y的最長公共子串行矛盾,所以①成立。
②由已知,假設zk不是xm-1和yn的最長公共子串行,那麼存在乙個比zk更長的序列是xm-1和yn的公共子串行,而這個更長的序列肯定也是xm和yn的公共子串行,這個序列長度 > 原來z序列,與z是x和y的最長公共子串行矛盾,所以②成立。
③ 同②。
三、遞迴方程
用c[i][j]表示xi和yj的最長公共子串行的長度。
0 if i = 0 or j = 0
c[i][j] = c[i-1][j-1] + 1 if i,j>0 and xi= yj
max if i,j>0 and xi ≠ yj
四、 python**實現(包括輸出最長公共子串行)
import copy
def dplength(x, y, c, b):
for i in range(1, m+1):
for j in range(1, n+1):
if x[i-1] == y[j-1]:
c[i][j] = c[i-1][j-1] + 1
b[i][j] = 1 # 1表示該字元是在公共子串行當中的
elif c[i-1][j] >= c[i][j-1]:
c[i][j] = c[i-1][j]
b[i][j] = 0 # 0表示不在公共子串行中
else:
c[i][j] = c[i][j-1]
b[i][j] = 2 # 2表示不在公共子串行但與0不同
return b and c
def printlcs(b, x, i, j): #列印重複部分
if i == 0 or j == 0:
return 0
if b[i][j] == 1:
printlcs(b, x, i-1, j-1)
print(x[i-1]) #注意二維列表中的i、j與x、y序列(列表)差1
elif b[i][j] == 0:
printlcs(b, x, i-1, j)
else:
printlcs(b, x, i, j-1)
if __name__ == '__main__':
x = list(input())
y = list(input())
print(x)
print(y)
m = len(x)
n = len(y)
c = [ for i in range(m+1)]
for i in range(m+1):
for j in range(n+1):
b = copy.deepcopy(c)
dplength(x, y, c, b)
printlcs(b, x, m, n)
print(c)
print("x在y中的重複率達到:", c[m][n]/n*100, "%")
print("y在x中的重複率達到:", c[m][n]/m*100, "%")
五、實驗結果
輸入:x:abcbdab
y: bdcaba
輸出:abcbdab
bdcaba
['a', 'b', 'c', 'b', 'd', 'a', 'b']
['b', 'd', 'c', 'a', 'b', 'a']
[[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0]]bc
ba[[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1], [0, 1, 1, 1, 1, 2, 2], [0, 1, 1, 2, 2, 2, 2], [0, 1, 1, 2, 2, 3, 3], [0, 1, 2, 2, 2, 3, 3], [0, 1, 2, 2, 3, 3, 4], [0, 1, 2, 2, 3, 4, 4]]
[[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 2, 1], [0, 1, 2, 2, 0, 1, 2], [0, 0, 0, 1, 2, 0, 0], [0, 1, 0, 0, 0, 1, 2], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 1], [0, 1, 0, 0, 0, 1, 0]]
x在y中的重複率達到: 66.66666666666666 %
y在x中的重複率達到: 57.14285714285714 %
process finished with exit code 0
最長公共子串行python實現
最長公共子串行是動態規劃基本題目,下面按照動態規劃基本步驟解出來。序列a共有m個元素,序列b共有n個元素,如果a m 1 b n 1 那麼a m 和b n 的最長公共子串行長度就是a m 1 和b n 1 的最長公共子串行長度 1 如果a m 1 b n 1 那麼a m 和b n 的最長公共子串行長...
最長公共子串行python實現
1 dp基本思路 公共子串行最優子結構 將問題分解表成更簡單的子問題,這個子問題可以分解成更多的子問題使用動態規劃演算法求解,這個過程需要在乙個表中儲存同一級別的子問題的解,因此這個解可以被更高階的子問題使用。2 問題的解 定義兩個序列x y,二維陣列f i j 表示x的i位和y的j位之前的最長公共...
python實現最長公共子串行
最長公共子串行python實現,最長公共子串行是動態規劃基本題目,下面按照動態規劃基本步驟解出來。1.找出最優解的性質,並刻劃其結構特徵 序列a共有m個元素,序列b共有n個元素,如果a m 1 b n 1 那麼a m 和b n 的最長公共子串行長度就是a m 1 和b n 1 的最長公共子串行長度 ...