最長公共子串行的問題常用於解決字串的相似度,是乙個非常實用的演算法,作為碼農,此演算法是我們的必備基本功。
二:概念
舉個例子,
cnblogs
這個字串中子序列有多少個呢?很顯然有2
7個,比如其中的cb,cgs等等都是其子序列,我們可以看出
子串行不見得一定是連續的,連續的那是子串。
在你找出的公共子串行中,你能找出最長的公共子串行嗎?
從圖中我們看到了最長公共子串行為blog,仔細想想我們可以發現其實最長公共子串行的個數不是唯一的,可能會有兩個以上,
但是長度一定是唯一的,比如這裡的最長公共子串行的長度為4。
三:解決方案
<1> 列舉法
這種方法是最簡單,也是最容易想到的,當然時間複雜度也是龜速的,我們可以分析一下,剛才也說過了cnblogs的子串行
個數有27個 ,延伸一下:乙個長度為n的字串,其子序列有2n個,每個子串行要在第二個長度為n的字串中去匹配,匹配一次
需要o(n)的時間,總共也就是o(n*2n),可以看出,時間複雜度為指數級,恐怖的令人窒息。
<2> 動態規劃
既然是經典的題目肯定是有優化空間的,並且解題方式是有固定流程的,這裡我們採用的是矩陣實現,也就是二維陣列。
第一步:先計算最長公共子串行的長度。
第二步:根據長度,然後通過回溯求出最長公共子串行。
現有兩個序列x=,y=,
設乙個c[i,j]: 儲存xi與yj的lcs的長度。
遞推方程為:
不知道大家看懂了沒?動態規劃的乙個重要性質特點就是解決「子問題重疊」的場景,可以有效的避免重複計算,根據上面的
公式其實可以發現c[i,j]一直儲存著當前(xi,yi)的最大子串行長度。
using system;
3 ", martix[str1.length, str2.length]);
19 20 console.read();
21 }
22 23 static void lcs(string str1, string str2)
24
42 else
43
50 }
51 }
52 }
53 }
54 }
圖大家可以自己畫一畫,**完全是根據上面的公式照搬過來的,長度的問題我們已經解決了,這次要解決輸出最長子序列的問題,
我們採用乙個標記函式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]例如:我輸入兩個序列x=acgbfhk,y=cegefkh。
using system;
2 4
28 29 static void lcs(string str1, string str2)
30
49 else
50
57 else
58
62 }
63 }
64 }
65 }
66 67 static void subsequence(int i, int j)
68 : 當前座標:(,)", str2[j - 1], i - 1, j - 1);
75 76 //左前方
由於直接繪圖很麻煩,嘿嘿,我就用手機拍了張:
好,我們再輸入兩個字串:
通過上面的兩張圖,我們來分析下它的時間複雜度和空間複雜度。
時間複雜度:構建矩陣我們花費了o(mn)的時間,回溯時我們花費了o(m+n)的時間,兩者相加最終我們花費了o(mn)的時間。
空間複雜度:構建矩陣我們花費了o(mn)的空間,標記函式也花費了o(mn)的空間,兩者相加最終我們花費了o(mn)的空間。
3動態規劃求公共最長子序列
這是一道求公共最長子序列的題,首先要區別子串行與字串。子串行是可以不連續的,而字串一定是連續的。思路 動態規劃 二維圖 例子 輸入兩個字串s1,s2,cin就可以解決,之後進行動態規劃。如圖建立dp二維陣列來記錄。當比較到字元相同時,dp i j 這個位置的數是取dp i 1 j dp i j dp...
最長連續公共最長子序列
阿里筆試題 給定乙個 query 和乙個 text,均由小寫字母組成。要求在 text 中找出以同樣的順序連 續出現在 query 中的最長連續字母序列的長度。例如,query 為 acbac text 為 acaccbabb 那麼 text 中的 cba 為最長的連續出現在 query 中的字母序...
求最長子序列和最長公共子串
又有一段時間沒刷題,今天溫故下,最長公共子串行和最長公共子串概念不一樣,子串行可以不連續,子串必須連續,這兩題均可以用動態規劃解決!下面程式在vs上跑過無問題!include include include includeusing namespace std 動態規劃求最長子序列 int long...