题目
如果字符串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 }