描述
我们称序列 Z = < z1, z2, …, zk >是序列X = < x1, x2, …, xm >的子序列当且仅当存在严格上升的序列< i1, i2, …, ik >,使得对j = 1, 2, … ,k, 有xij = zj。比如Z = < a, b, f, c > 是X = < a, b, c, f, b, c >的子序列。
现在给出两个序列X 和Y,你的任务是找到X 和Y 的最大公共子序列,也就是说要找到一个最长的序列Z,使得Z 既是X 的子序列也是Y 的子序列。
输入
输入包括多组测试数据。每组数据包括一行,给出两个长度不超过200 的字符串,表示两个序列。两个字符串之间由若干个空格隔开。
输出
输入包括多组测试数据。每组数据包括一行,给出两个长度不超过200 的字符串,表示两个序列。两个字符串之间由若干个空格隔开。
样例输入
abcfbc abfcab
programming contest
abcd mnp
样例输出
4
2
0
分析
状态:maxLen[i][j]表示字符串a左边i个字符与字符串b左边j的字符形成的子串的最大公共子序列长度 (i, j >= 0)。
状态转移方程:
if(str1[i-1] == str2[j-1])
maxLen[i][j] = maxLen[i-1][j-1]+1;
else
maxLen[i][j] = max{maxLen[i][j-1], maxLen[i-1][j]}
实现
此题未给字符串的长度范围,所以我们可以把数据设大些。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
char str1[1000];
char str2[1000];
int maxLen[1000][1000];
int main() {
while (cin >> str1 >> str2) {
int length1 = strlen(str1);
int length2 = strlen(str2);
for (int i = 0; i <= length1; i++)
maxLen[i][0] = 0;
for (int j = 0; j <= length2; j++)
maxLen[0][j] = 0;
for (int i = 1; i <= length1; i++) {
for (int j = 1; j <= length2; j++) {
if (str1[i - 1] == str2[j - 1])
maxLen[i][j] = maxLen[i - 1][j - 1] + 1;
else
maxLen[i][j] = max(maxLen[i][j - 1], maxLen[i - 1][j]);
}
}
cout << maxLen[length1][length2] << endl;
}
return 0;
}
还有不假定长度范围的版本,速度会慢些,但也可以通过测试。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
string str1, str2;
int main()
{
// freopen("in.txt", "r", stdin);
while (cin >> str1 >> str2) {
const int str1Length = str1.length();
const int str2Length = str2.length();
int sencondLength = str2Length + 1;
//用一维数组模拟二维数组
int *maxLen = new int[sencondLength * (str1Length + 1)];
//边界条件
for (int i = 0; i <= str1Length; i++) {
maxLen[sencondLength * i + 0] = 0;
}
for (int j = 0; j <= str2Length; j++) {
maxLen[sencondLength * 0 + j] = 0;
}
for (int i = 1; i <= str1Length; i++) {
for (int j = 1; j <= str2Length; j++) {
//状态转移方程
if (str1[i - 1] == str2[j - 1]) {
maxLen[sencondLength * i + j] = maxLen[sencondLength * (i - 1) + (j - 1)] + 1;
}
else {
maxLen[sencondLength * i + j] = max(maxLen[sencondLength * i + (j - 1)], maxLen[sencondLength * (i - 1) + j]);
}
}
}
cout << maxLen[sencondLength * str1Length + str2Length] << endl;
delete[] maxLen;
}
return 0;
}