乙個給定序列的子串行是在該序列中刪除若干元素後得到的序列,確切的說,若給定序列x = ,則另乙個序列,y= ,當另乙個序列即是x的子串行又是y的子串行時,稱z是序列x也y的公共子串行。最長公共子串行問題為給定序列x和y,找到所有公共子串行中最長的乙個(非連續)。
解最長公共子串行問題的最容易想到的方法是窮舉法,即對x的所有子串行,檢查它是否也是y 的子串行,從而確定它是否為x和y 的公共子串行,並且在檢查過程中記錄最長的公共子串行。x的所有子串行檢查過後即可求出x和y 的最長公共子串行。x的沒個子序列相應於下標集的乙個子集。因此,公有2**m個不同的子串行,從而窮舉法需要指數時間。
事實上,最長公共子串行問題具有最優子結構性質:
設序列x=和y= 的乙個最長公共子串行為z=,則
(1) 若xm=yn ,則zk=xm=yn,且zk-1是xm-1和yn-1的最長公共子串行。
(2)若xm≠yn,且zk≠xm,則z是xm-1和y的最長公共子串行。
(3)若xm≠yn且zk≠yn,則z是x和yn-1的最長公共子串行。
證明略由最長公共子串行問題的最優子結構性質可知,要找出x=和y=的最長公共子串行,可以按照以下方式遞迴的進行:當xm=yn時,找出xm-1和yn-1的最長公共子串行,然後在其尾部加上xm(=yn)即可得到x和y的乙個最長公共子串行,當xm≠yn時,必須接兩個字問題,也就是要找出xm-1和yn的乙個最長公共子串行已經xm和yn-1的乙個最長公共子串行。並求兩個子問題公共子串行最長的。用c[i][j]記錄序列的xi和yj的最長公共子串行的長度,其中xi=;yj=,當i=0或j=0時,空序列是xi和yj的最長公共子串行故此時c[i][j]=0,由最優子結構性質可建立遞迴關係如下:
直接利用遞迴關係式容易寫出乙個計算c[i][j]的遞迴演算法,但其計算時間是隨輸入長度指數增長的,由於在考慮的子問題空間中,總共有φ(mn)個不同的子問題,因此,用動態規劃演算法由底向上計算最優值能提高演算法的效率。
計算最長公共子串行長度的動態規劃演算法lcslength以序列x=和y=最為輸入,暑促兩個陣列c和b,其中c[i][j]儲存xi和yj的最長公共子串行的的長度,b[i][j]記錄c[i][j]的值是由哪乙個子問題解決得到的。具體**實現如下(python)
def lcslength(m, n, x=none, y=none,c=none, b=none):
for i in range(1, m):
for j in range(1, n):
if x[i-1] == y[j-1]:
c[i][j] = c[i-1][j-1]+1
b[i][j] = 'equals'
elif c[i-1][j] >= c[i][j-1]:
c[i][j] = c[i-1][j]
b[i][j] = 'up'
else:
c[i][j] = c[i][j-1]
b[i][j] = 'left'
由演算法lcslength計算得到的陣列b可用於快速構造序列x=和y=的最長公共子串行。首先從b[m][n]開始,根據b[i][j]值所指向的方向進行搜尋。equals表示等於,即x和y的最長公共子串行為xi-1和yj-1的最長公共子串行加上xi所得的最長公共子串行,left為向左,即xi和yj的最長公共子串行與xi和yj的最長公共子串行相同,up表示向上,即xi和yj的最長公共子串行與xi-1和yj的最長公共子串行相同。下面lcs演算法為具體的求解過程。
def getlcs(i, j, x=none, b=none):
if i == 0 and j == 0:
return
if b[i][j] == 'equals':
getlcs(i-1,j-1, x, b)
print x[i-1], ' '
elif b[i][j] == 'left':
getlcs(i, j-1, x, b)
else:
getlcs(i-1, j, x, b)
現有兩個序列x=和y=,由演算法lcslength和lcs計算出的結果如圖所示:
#-*-coding:utf8-*-
"""author : xianghonglee
email : [email protected]
created on '14-5-26'
"""def lcslength(m, n, x=none, y=none,c=none, b=none):
for i in range(1, m):
for j in range(1, n):
if x[i-1] == y[j-1]:
c[i][j] = c[i-1][j-1]+1
b[i][j] = 'equals'
elif c[i-1][j] >= c[i][j-1]:
c[i][j] = c[i-1][j]
b[i][j] = 'up'
else:
c[i][j] = c[i][j-1]
b[i][j] = 'left'
def getlcs(i, j, x=none, b=none):
if i == 0 and j == 0:
return
if b[i][j] == 'equals':
getlcs(i-1,j-1, x, b)
print x[i-1], ' '
elif b[i][j] == 'left':
getlcs(i, j-1, x, b)
else:
getlcs(i-1, j, x, b)
if __name__ == '__main__':
x ="abcbdab"
y = "bdcaba"
m = len(x)+1
n = len(y)+1
b = [[0 for i in range(n)] for j in range(m)]
c = [[0 for i in range(n)] for j in range(m)]
lcslength(m,n,x,y,c,b)
for i in c:
print i
for j in b:
print j
getlcs(m-1,n-1,x,b)
列印結果為:
python 最長公共子串行
usr bin env python3 coding utf 8 最長公共子串行 fish fosh fsh def findlongestsubstring source,dest 輸入值,要比較的值 inlen len source outlen len dest target cell 0 f...
最長公共子串行 最長公共子串
1 最長公共子串行 採用動態規劃的思想,用乙個陣列dp i j 記錄a字串中i 1位置到b字串中j 1位置的最長公共子串行,若a i 1 b j 1 那麼dp i j dp i 1 j 1 1,若不相同,那麼dp i j 就是dp i 1 j 和dp i j 1 中的較大者。class lcs el...
最長公共子串行 最長公共子串
1.區別 找兩個字串的最長公共子串,這個子串要求在原字串中是連續的。而最長公共子串行則並不要求連續。2 最長公共子串 其實這是乙個序貫決策問題,可以用動態規劃來求解。我們採用乙個二維矩陣來記錄中間的結果。這個二維矩陣怎麼構造呢?直接舉個例子吧 bab 和 caba 當然我們現在一眼就可以看出來最長公...