動態規劃之最長公共子序列&最長公共子串
題目
如果字串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 }