参考资料:(76条消息) 动态规划解最长公共子序列(LCS)(附详细填表过程)_z-k的博客-CSDN博客_最长公共子序列动态规划算法
思路:比对目标序列,动态规划求打分矩阵
矩阵中每个位置上的值来自左上,左或上方的值
字符两两对应相同的值 为左上角加1,不相同的取左或上方的最大值
几个易错点:
1.
使用for循环进行序列比对时,序列字符的下标并不是矩阵的下标[i][j],而是[i+1][j+1]
为了使打分过程比较直观,采用对矩阵单独设置下标的方法:
i,j序列下标,o,d矩阵下标
int o=0;int d=0;
for(int i=0;i<s1;i++){
o++;d=0;
for(int j=0;j<s2;j++){
d++;
}
}
2.找到矩阵的最大值位置后,如何其在确定序列中的位置
找到的max所在的行数为13(下标为12)
实际在str1中的位置是第12个(下标为11)
共有10个
则在str1中的最大公共子序列为从x--y
y=11;x=y-max+1;
代码:#include <stdio.h> #include <string.h> #include <math.h> int max(int a, int b) { if (a > b) { return a; } else { return b; } } int main() { int dp[100][100]; char s1[100] = "eryghdjfhiii"; int n1 = strlen(s1); char s2[100] = "yghdjfhiiier"; int n2 = strlen(s2); for (int q1 = 0; q1 <= n1; q1++) { for (int q2 = 0; q2 <= n2; q2++) { dp[q1][q2] = 0; } } int o = 0; int d = 0; for (int i = 0; i < n1; i++) { o++; d = 0; for (int j = 0; j < n2; j++) { d++; if (s1[i] == s2[j]) { dp[o][d] = dp[o - 1][d - 1] + 1; } else { dp[o][d] = max(dp[o - 1][d], dp[o][d - 1]); } } } for (int p = 0; p <= n1 ; p++) { for (int q = 0; q <= n2; q++) { printf("%d ", dp[p][q]); } printf("\n"); } int max = 0, a; for (int w = 1; w <= n1; w++) { for (int f = 1; f <= n2; f++) { if (dp[w][f] > max) { max = dp[w][f]; a = w; } } } printf("a=%d,max=%d\n", a, max); int y1 = a - 1; int x1 = y1 - max + 1; printf("x1=%d,y1=%d\n", x1, y1); for (int e = x1 ; e <= y1; e++) { printf("%c", s1[e]); } }
结果:
![]()