最长公共子序列问题|最长公共子串问题|动态规划
Longest Common Subsequence Problem
序列X和Y,找到Z为X和Y的最大公共子序列
蛮力枚举
从X的长度为1序列开始枚举,在Y中查找是否有该序列
枚举观察,长度为x-1的子序列是长度为x的子序列的一部分
存在最优子结构和重叠子问题,适合动态规划
1、问题结构分析
C[i,j]记录X[1..i]和Y[1..j]的最长公共子序列长度
2、通过考察末尾元素来寻找递推关系
有Xi=Yj和Xi≠Yj两种情况
Xi≠Yj时,C[i,j]= max(C[i-1,j],C[i, j-1])
Xi=Yj时,C[i,j]=max(C[i-1, j-1]+1,C[i-1, j],C[i,j-1])
由于C[i-1, j-1]+1>=max{C[i,j-1],c[i-1,j]}
则 Xi=Yj时,C[i,j]= C[i-1, j-1]+1
3、自底向上计算:确定计算顺序
初始化 C[i,0]=C[0,j]=0
递推公式 得出计算顺序自上而下自左而右
4、追踪数组rec[i,j]=LU / U/ L
时间复杂度O(n*m),n、m分别为序列X、Y的长度
#include<stdio.h>
#define MAX 1000
int x[MAX], y[MAX], z[MAX][MAX], rec[MAX][MAX];
int xl, yl;
int longestSub(){
int i, j, res;
// for(i=0; i<=xl; i++) z[i][0]=0;//初始化
// for(i=0; i<=yl; i++) z[0][i]=0;
for(i=1; i<=xl; i++){
for(j=1; j<=yl; j++){
if(x[i]==y[j]){
z[i][j]=z[i-1][j-1]+1;
rec[i][j]=1;
}
else if(z[i-1][j]>=z[i][j-1]){
z[i][j]=z[i-1][j];
rec[i][j]=2;
}
else{
z[i][j]=z[i][j-1];
rec[i][j]=3;
}
}
}
return z[xl][yl];
}
void printSub(int i, int j){
if(i==0||j==0) return ;
if(rec[i][j]==1){
printSub(i-1, j-1);
printf("%d ", x[i]);
}
else if(rec[i][j]==2) printSub(i-1, j);
else printSub(i, j-1);
}
int main(){
int i, j, res;
scanf("%d%d", &xl, &yl);
for(i=1; i<=xl; i++) scanf("%d", &x[i]);
for(i=1; i<=yl; i++) scanf("%d", &y[i]);
res=longestSub();
printf("最长公共子序列长度为%d:\n",res);
printSub(xl, yl);
return ;
}
Longest Common Substring Problem
蛮力枚举观察知
存在最优子结构和重叠子问题,适用动态规划
C[i,j]表示X[1..i]和Y[1..j]中,以 Xi和Yj结尾的最长公共子串 Z[1..l]的长度
Xi≠Yj时,C[i][j]=0
Xi=Yj时,C[i][j]=C[i-1][j-1]+1
初始化 C[i,0]=C[0,j]=0
递推式
自上而下自左而右计算
追踪最优方案
最长公共子串末尾位置Pmax,最长公共子串长度Lmax
#include<stdio.h>
#define MAX 1000
int x[MAX], y[MAX], c[MAX][MAX];
int xl, yl, pmax=0, lmax=0;
void LongestSubstr(){
int i, j;
// for(i=0; i<=xl; i++) c[i][0]=0;
// for(i=0; i<=yl; i++) c[0][i]=0;
for(i=1; i<=xl; i++){
for(j=1; j<=yl; j++){
if(x[i]==y[j]){
c[i][j]=c[i-1][j-1]+1;
if(c[i][j]>=lmax){
lmax=c[i][j];
pmax=i;
}
}
else c[i][j]=0;
}
}
return ;
}
int main(){
int i;
scanf("%d%d", &xl, &yl);
for(i=1; i<=xl; i++) scanf("%d",&x[i]);
for(i=1; i<=yl; i++) scanf("%d", &y[i]);
LongestSubstr();
for(i=pmax-lmax+1; i<=pmax; i++) printf("%d ", x[i]);
return 0;
}

浙公网安备 33010602011771号