1. 程式人生 > >動態規劃之最長公共子序列&最長公共子串

動態規劃之最長公共子序列&最長公共子串

題目

  如果字串1的所有字元按其在字串中的順序出現在另外一個字串2中,則字串1稱之為字串2的子序列。

  注意,並不要求子子序列(字串1)的字元必須連續出現在字串2中。

  請編寫一個函式,輸入兩個字串,求它們的最長公共子串,並打印出最長公共子序列。

  例如:輸入兩個字串BDCABA和ABCBDAB,字串BCBA和BDAB都是是它們的最長公共子序列,則輸出它們的長度4,並列印任意一個子序列。

分析

  本問題是典型的動態規劃問題,子字串的最優解為字串提供了決策依據。有兩個字串str1和str2,設c[i,j]為子串str1[0-i]和str2[0-j]的最長公共子序列的長度,

  如果str1[i]=str2[j],則c[i,j]=c[i-1,j-1]+1;

  如果str1[i]!=str2[j],則c[i,j]要麼等於str1[0,i-1]和str2[0,j]的最長公共子序列的長度,要麼等於str1[0,i]和str2[0,j-1]的最長公共子序列的長度,取兩者的最大值即是c[i,j]

  如圖一個示例

        

  狀態轉移方程:

  c[0,j]=0;

  c[i,0]=0;

  c[i,j]=c[i-1,j-1]+1, 若str1[i]=str2[j];

  c[i,j]=max{c[i-1,j],c[i,j-1]}

程式碼

複製程式碼
 1 int Lcslen(char* stra,char* strb,int** c)
 2 {
 3     int len_a=strlen(stra);
4 int len_b=strlen(strb); 5 6 for(int i=1;i<=len_a;i++) 7 { 8 for(int j=1;j<=len_b;j++) 9 { 10 if(stra[i-1]==strb[j-1]) 11 { 12 c[i][j]=c[i-1][j-1]+1; 13 }else 14 { 15 c[i][j]=(c[i][j-1
]>c[i-1][j])?c[i][j-1]:c[i-1][j]; 16 } 17 } 18 } 19 20 return c[len_a][len_b]; 21 } 22 23 void lcs(char* stra,char* strb) 24 { 25 if(stra==NULL||strb==NULL) 26 return; 27 int len_a=strlen(stra); 28 int len_b=strlen(strb); 29 int** c=new int*[len_a+1]; 30 for (int i=0;i<=len_a;i++) 31 { 32 c[i]= new int[len_b+1](); 33 } 34 35 int k=Lcslen(stra,strb,c); 36 37 char* lcs=new char[k]; 38 39 int i=len_a+1; 40 int j=len_b+1; 41 while(k>=0) 42 { 43 if(c[i][j]==c[i][j-1]) 44 { 45 j--; 46 }else if(c[i][j]==c[i-1][j]) 47 { 48 i--; 49 }else if(c[i][j]==c[i-1][j-1]) 50 { 51 lcs[k--]=stra[i-1]; 52 i--; 53 j--; 54 } 55 } 56 57 for (int i=0;i<=len_a;i++) 58 { 59 delete[] c[i]; 60 } 61 delete[] c; 62 }
複製程式碼

動態規劃之最長公共子串

  本題和上題的區別是子串要求是連續的。那麼當str1[i]!=str2[j]的時候,前面的公共子串到此結束,c[i,j]重新等於0,開始尋找下一個公共子串。

  狀態轉移方程式變為:

  c[0,j]=0;

  c[i,0]=0;

  c[i,j]=c[i-1,j-1]+1, 若str1[i]==str2[j];

  c[i,j]=0, 若str1[i]!=str2[j]

  最大子串長度max_dis=max{c[i][j]}

程式碼

複製程式碼
 1 int ContinuousLCS(char* stra,char* strb)
 2 {
 3     if(stra==NULL||strb==NULL)
 4         return -1;
 5 
 6     int len_a=strlen(stra);
 7     int len_b=strlen(strb);
 8 
 9     //new space of int[][]
10     int** c=new int*[len_a+1];
11     for (int i=0;i<=len_a;i++)
12     {
13         c[i]=  new int[len_b+1]();
14     }
15 
16     int max_dis=0,index=0;
17     for(int i=1;i<=len_a;i++)
18     {
19         for(int j=1;j<=len_b;j++)
20         {
21             if(stra[i-1]==strb[j-1])
22             {
23                 c[i][j]=c[i-1][j-1]+1;
24             }else
25             {
26                 c[i][j]=0;
27             }
28 
29             if (max_dis<=c[i][j])
30             {
31                 max_dis=c[i][j];
32                 index=i;
33             }
34         }
35 
36     }
37 
38     //output result
39     for (int i=index-max_dis;i<index;i++)
40     {
41         cout<<stra[i]<<' ';
42     }
43     cout<<endl;
44 
45     //free
46     for (int i=0;i<=len_a;i++)
47     {
48         delete[] c[i]; 
49     }
50     delete[] c;
51 
52     return max_dis;
53 }