-
描述
-
我们称序列Z = < z
1, z
2, ..., z
k >是序列X = < x
1, x
2, ..., x
m >的子序列当且仅当存在
严格上升 的序列< i
1, i
2, ..., i
k >,使得对j = 1, 2, ... ,k, 有x
ij = z
j。比如Z = < a, b, f, c > 是X = < a, b, c, f, b, c >的子序列。
现在给出两个序列X和Y,你的任务是找到X和Y的最大公共子序列,也就是说要找到一个最长的序列Z,使得Z既是X的子序列也是Y的子序列。
输入
- 输入包括多组测试数据。每组数据包括一行,给出两个长度不超过200的字符串,表示两个序列。两个字符串之间由若干个空格隔开。 输出
- 对每组输入数据,输出一行,给出两个序列的最大公共子序列的长度。 样例输入
-
abcfbc abfcab programming contest abcd mnp
样例输出
-
4 2 0
解题思路:求两个字符串(s1,s2)的最长公共子串的长度。借助二维数组mark[][],记录每个位置的最大子串长度。
如果 s1[i]=s2[j] mark[i][j] = mark[i-1][j-1];
否则 mark[i][j] = max(mark[i-1][j], mark[i][j-1]);
例如:s1="abcfbc" ; s2="abfcab";
a b f c a b
| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
a | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
b | 0 | 1 | 2 | 2 | 2 | 2 | 3 |
c | 0 | 1 | 2 | 2 | 3 | 3 | 3 |
f | 0 | 1 | 2 | 3 | 3 | 3 | 3 |
b | 0 | 1 | 2 | 3 | 3 | 3 | 4 |
c | 0 | 1 | 2 | 3 | 4 | 4 | 4 |
最长公共子串的长度即使mark[ len1 ][ len2 ]的值;
注:s1、s2字符串从s1+1、s2+1开始输入,输入格式:scanf("%s",s1+1);scanf("%s",s2+1);
时间复杂度O(n^2),空间复杂度O(n^2);
代码:
#include<stdio.h>
#include<string.h>
#define N 205
#define max(a,b) (a>b ? a : b)
int main(){
int i, j;
char s1[N], s2[N];
int mark[N][N]; //mark[i][j]标记当前i,j位置的最长子串长度
while(~scanf("%s", s1+1)){
scanf("%s", s2+1);
int len1 = strlen(s1+1); //求字符串s1的长度
int len2 = strlen(s2+1); //求字符串s2的长度
memset(mark ,0, sizeof(mark)); //初始化mark[][]
for(i = 1; i <= len1; i ++){
for(j = 1; j <= len2; j ++){
if(s1[i] == s2[j]) //如果s1的第i个字符等于s2的第j个字符
mark[i][j] = mark[i-1][j-1] + 1;
else
mark[i][j] = max(mark[i][j-1], mark[i-1][j]);
}
}
printf("%d\n", mark[len1][len2]);
}
return 0;
}