最長公共子序列(LCS)是典型的動態規劃問題,如果不理解動態規劃請移步先看這篇動態規劃的總結,否則本篇文章中的程式碼實現會不理解的喲!
LCS問題的一個變種就是求最長單調遞增子序列,它的一種簡易求解方法就是先將原序列A進行排序得到序列B,然後求解序列A和序列B的最長公共子序列。
1.問題描述
2.最優子結構和子問題重疊
3.5種實現方式
根據LCS的遞推公式
(1)從中可以看出計算c[i][j]時只需要2行即可,前一行(i-1)和當前行(i),每行的長度是min{m,n},首先初始化前一行都為0,然後計算當前行的值,當要計算下一行之前將當前行的值複製到前一行中即可。
(2)從遞推公式中還可以看出計算當前行i的話,其實只需要一行再加上O(1)的額外空間就行了。因為計算c[i][j]只需要前一行中c[i-1][k] (k>=j-1)的資料,對於k<j-1的資料都是沒有用的,而當前行c[i]l的資料都是有用的,要用來計算下一行的值,所以,可以在計算當前行的時候,將當前行的前面計算好的部分複製到前一行中對應位置上,但是c[i][j-1]除外,因為c[i-1][j-1]也是需要的,所以需要額外的O(1)的空間儲存c[i][j-1]。
LCS的五種實現:分別為0:直接遞迴;1:帶備忘錄的遞迴;2:使用二維陣列儲存結果的迭代;3:使用2個一維陣列儲存結果的迭代;4:使用1個一維陣列和額外的O(1)空間儲存結果的迭代。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
def lcs0(i,j): #string starts at index 0, not 1 if i<0 or j<0: return 0 #attention to this!!! if x[i]==y[j]: return lcs0(i-1,j-1)+1 return max(lcs0(i-1,j),lcs0(i,j-1)) x,y='abcde','oaob' lenx,leny=len(x),len(y) print(lcs0(lenx-1,leny-1)) #2 from functools import wraps def memo(func): cache={} @wraps(func) def wrap(*args): if args not in cache: cache[args]=func(*args) return cache[args] return wrap <a href='http://www.jobbole.com/members/oh_yibin'>@memo</a> def lcs1(i,j): #string starts at index 0, not 1 if i<0 or j<0: return 0 #attention to this!!! if x[i]==y[j]: return lcs1(i-1,j-1)+1 return max(lcs1(i-1,j),lcs1(i,j-1)) x,y='abcde','oaob' lenx,leny=len(x),len(y) print(lcs1(lenx-1,leny-1)) #2 def lcs2(x,y): lenx,leny=len(x),len(y) minlen,maxlen=0,0 if lenx<leny: minlen,maxlen=lenx,leny; x,y=y,x else: minlen,maxlen=leny,lenx; #s is maxlen * minlen s=[[0 for j in range(minlen)] for i in range(maxlen)] for i in range(maxlen): #so, let x be the longer string!!! for j in range(minlen): if x[i]==y[j]: s[i][j]=s[i-1][j-1]+1 else: s[i][j]=max(s[i-1][j],s[i][j-1]) return s x,y='abcde','oaob' s=lcs2(x,y) print(s) #[[0, 1, 1, 1], [0, 1, 1, 2], [0, 1, 1, 2], [0, 1, 1, 2], [0, 1, 1, 2]] def lcs3(x,y): lenx,leny=len(x),len(y) minlen,maxlen=0,0 if lenx<leny: minlen,maxlen=lenx,leny; x,y=y,x else: minlen,maxlen=leny,lenx; #s is maxlen * minlen pre=[0 for j in range(minlen)] cur=[0 for j in range(minlen)] for i in range(maxlen): #so, let x be the longer string!!! for j in range(minlen): if x[i]==y[j]: cur[j]=pre[j-1]+1 else: cur[j]=max(pre[j],cur[j-1]) pre[:]=cur[:] return cur x,y='abcde','oaob' s=lcs3(x,y) print(s) #[2, 2, 2, 2] def lcs4(x,y): lenx,leny=len(x),len(y) minlen,maxlen=0,0 if lenx<leny: minlen,maxlen=lenx,leny; x,y=y,x else: minlen,maxlen=leny,lenx; #s is maxlen * minlen s=[0 for j in range(minlen)] t=0 for i in range(maxlen): #so, let x be the longer string!!! for j in range(minlen): if x[i]==y[j]: s[j]=t+1 else: s[j]=max(s[j],s[j-1]) t=s[j] return s x,y='abcde','oaobce' s=lcs4(x,y) print(s) #[3, 3, 3, 3, 4] |
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!