动态规划——最长公共子序列
算法思想:用一个二维数组c来表示两个串的字串的公共子序列个数,比如c[i][j]表示的是,x[0…i]和y[0…j]的最长公共子串,因为当任意子串长度为0时,没有公共子序列,可以得:c[0][0…n]=0,c[0…m][0]=0(m,n为字符串x,y的长度),
当x[i]==y[j]时,也就是说,两个子串的最后一个字符相同,他们的最长公共子序列一定包含了x[i],显然,c[i][j]=c[i-1][j-1]+1,即当前的子串的最长公共子序列,等于两个子串长度-1的最长公共子序列,再+1(因为我们减去的x[i]和y[j]相等,是他们的公共子序列),
当[i]!=y[j]时,c[i][j]=max{c[i-1][j],c[i][j-1]},两个子串的最后一个元素不同,所以,两个子串的最大公共子序列的最后一个元素一定不是他们的最后一个元素,因为他们根本就不等,怎么可能成为一个公共元素,只有可能是c[i-1][j]或c[i][j-1],也就是其中一个子串最后一个元素不构成子串的最大公共子序列,再取两者的最大值即可。
b[i][j]用来记录c[i][j]的值是由哪个子问题得到的,由LCS()来得出最长公共子序列。
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
void LCSLength(int m,int n,char* x,char* y,int** c,int** b){
int i,j;//i,j为两个字符串的下标,c[i][j]为当str1和str2长度为i,j时的最长公共子序列
//当其中一个字符串为空时,没有公共子序列
for(i=0;i<=m;i++)
c[i][0] = 0;
for(j=0;j<=n;j++)
c[0][j] = 0;
/*DP求解,分两种情况:
1、x[i]==y[j],c[i][j] = c[i-1][j-1]+1
2、x[i]!=y[j],c[i][j] = max(c[i][j-1],c[i-1][j])
*/
for(i=1;i<=m;i++){
for(j=1;j<=n;j++){
if(x[i-1]==y[j-1]){
c[i][j]=c[i-1][j-1] + 1;
b[i][j]=1;
}
else{
if(c[i][j-1]>c[i-1][j]){
c[i][j]=c[i][j-1];
b[i][j]=2;
}
else{
c[i][j]=c[i-1][j];
b[i][j]=3;
}
}
}
}
printf("len=%d\n",c[m][n]);
}
void LCS(int i,int j,char* x,int **b){
if(i==0||j==0)
return;
if(b[i][j]==1){
LCS(i-1,j-1,x,b);
printf("%c",x[i-1]);
}
else if(b[i][j]==2)
LCS(i,j-1,x,b);
else
LCS(i-1,j,x,b);
}
int main(){
char x[100]={'\0'},y[100]={'\0'};
gets(x);
gets(y);
int m = strlen(x);
int n = strlen(y);
//二维数组c多申请一行一列,表示其中有字符串的长度为 0 ,b[i][j]数组记录c[i][j]是由哪个子问题的解得到的
int **c=(int **)malloc(sizeof(int *)*(m+1));
int **b=(int **)malloc(sizeof(int *)*(m+1));
for(int i = 0;i<m+1;i++){
c[i]=(int*)malloc(sizeof(int)*(n+1));
b[i]=(int*)malloc(sizeof(int)*(n+1));
}
LCSLength(m,n,x,y,c,b);
printf("string=");
LCS(m,n,x,b);
return 0;
}