最長公共子串行知識點

2021-07-16 13:54:31 字數 3217 閱讀 1306

動態規劃法解最長公共子串行

最長公共子串行與最長公共子串的區別在於

最長公共子串行不要求在原字串中是連續的

,比如ade和abcde的長公共子串行是ade。

我們用動態規劃的方法來思考這個問題如是求解。首先要找到狀態轉移方程:

經常會遇到複雜問題不能簡單地分解成幾個子問題,而會分解出一系列的子問題。簡單地採用把大問題分解成子問題,並綜合子問題的解匯出大問題的解的方法,問題求解耗時會按問題規模呈冪級數增加。

為了節約重複求相同子問題的時間,引入乙個陣列,不管它們是否對最終解有用,把所有子問題的解存於該陣列中,這就是動態規劃法所採用的基本方法。

【問題】 

求兩字串行的最長公共字元子串行

問題描述:字串行的子串行是指從給定字串行中隨意地(不一定連續)去掉若干個字元(可能乙個也不去掉)後所形成的字串行。令給定的字串行x=

「x0,x1

,…,xm-1」,序列y=

「y0,y1

,…,yk-1」是x

的子串行,存在x

的乙個嚴格遞增下標序列,i1

,…,ik-1>

,使得對所有的j=0

,1,…,k-1

,有xij=yj

。例如,x=

「abcbdab

」,y=

「bcdb

」是x的乙個子串行。

考慮最長公共子串行問題如何分解成子問題,設a=

「a0,a1

,…,am-1」,b=

「b0,b1

,…,bm-1」,並z=

「z0,z1

,…,zk-1」為它們的最長公共子串行。不難證明有以下性質:

(1) 

如果am-1=bn-1

,則zk-1=am-1=bn-1

,且「z0

,z1,…,zk-2」是「a0

,a1,…,am-2」和「b0

,b1,…,bn-2」的乙個最長公共子串行; (2

) 如果am-1!=bn-1

,則若zk-1!=am-1

,蘊涵「z0

,z1,…,zk-1」是「a0

,a1,…,am-2」和「b0

,b1,…,bn-1」的乙個最長公共子串行; (3

) 如果am-1!=bn-1

,則若zk-1!=bn-1

,蘊涵「z0

,z1,…,zk-1」是「a0

,a1,…,am-1」和「b0

,b1,…,bn-2」的乙個最長公共子串行。

這樣,在找a

和b的公共子串行時,如有am-1=bn-1

,則進一步解決乙個子問題,找「a0

,a1,…,am-2」和「b0

,b1,…,bm-2」的乙個最長公共子串行;如果am-1!=bn-1

,則要解決兩個子問題,找出「a0

,a1,…,am-2」和「b0

,b1,…,bn-1」的乙個最長公共子串行和找出「a0

,a1,…,am-1」和「b0

,b1,…,bn-2」的乙個最長公共子串行,再取兩者中較長者作為a

和b的最長公共子串行。(有助於理解)

對問題的另一版本解釋:

等號約定,c1是s1的最右側字元,c2是s2的最右側字元,s1『是從s1中去除c1的部分,s2'是從s2中去除c2的部分。

lcs(s1,s2)等於下列3項的最大者:

(1)lcs(s1,s2』)

(2)lcs(s1』,s2)

(3)lcs(s1』,s2』)--如果c1不等於c2; lcs(s1',s2')+c1--如果c1等於c2;

邊界終止條件:如果s1和s2都是空串,則結果也是空串。

下面我們同樣要構建乙個矩陣來儲存動態規劃過程中子問題的解。

這個矩陣中的每個數字代表了該行和該列之前(包括這行這列)的lcs的長度

。與上面剛剛分析出的狀態轉移議程相對應,矩陣中每個格仔裡的數字應該這麼填,它等於以下3項的最大值:

(1)上面乙個格仔裡的數字

(2)左邊乙個格仔裡的數字

(3)左上角那個格仔裡的數字(如果 c1不等於c2); 左上角那個格仔裡的數字+1( 如果c1等於c2)

舉個例子:

g  c  t  a

0  0  0  0  0

g  0  1  1  1  1

b  0  1  1  1  1

t  0  1  1  2  2

a  0  1  1  2  3

填寫最後乙個數字時,它應該是下面三個的最大者:

(1)上邊的數字2

(2)左邊的數字2

(3)左上角的數字2+1=3,因為此時c1==c2

所以最終結果是3。

在填寫過程中我們還是記錄下當前單元格的數字來自於哪個單元格,以方便最後我們回溯找出最長公共子串。有時候左上、左、上三者中有多個同時達到最大,那麼任取其中之一,但是在整個過程中你必須遵循固定的優先標準。在我的**中優先級別是左上》左》上。

下圖給出了回溯法找出lcs的過程:

模板 

#include#include#includeusing namespace std;

char a[1010];

char b[1010];

int dp[1010][1010];//dp[i][j]表示a序列第i位和b序列第j位之前(包括這一行這一列)的公共子串行長度;

int main()

else

}} printf("%d\n",dp[lena][lenb]);//注意輸出下標是lena,lenb;

} return 0;

}

還有一種當陣列較大時可以用滾動陣列:

**:

//求原串與逆序串的最大公共子串行 

#include#include#includeusing namespace std;

char str[5050],s[5050];

int dp[2][5050];

int main()

{ int n,i,j;

while(scanf("%d",&n)!=eof)

{ memset(dp,0,sizeof(dp));

scanf("%s",str);

for(i=0;i

最長公共子串行 最長公共子串

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 當然我們現在一眼就可以看出來最長公...

最長公共子串 最長公共子串行

子串要求連續 子串行不要求連續 之前的做法是dp求子序列 include include include using namespace std const int inf 0x3f3f3f3f const int mod 1000000007 string s1,s2 int dp 1010 10...