题目: 我们有两个字符串m和n,如果它们的子串a和b内容相同,则称a和b是m和n的公共子序列。子串中的字符不一定在原字符串中连续。
例如字符串“abcfbc”和“abfcab”,其中“abc”同时出现在两个字符串中,因此“abc”是它们的公共子序列。此外,“ab”、“af”等都是它们的字串。
现在给你两个任意字符串(不包含空格),请帮忙计算它们的最长公共子序列的长度。
示例1:
输入 :
abcfbc abfcab
programming contest
abcd mnp
输出:
4
2
0
动态规划思想
建立一个tmp矩阵,是两个字符串一个纵对应,一个横向对应。
tmp[i][j] 表示str1[0…i]和str2[0…j]的最长公共子序列的长度
求解 tmp[i][j]为:
- 如果str1[i] == str2[j],则 tmp[i][j] = max( tmp[i-1][j], tmp[i][j-1], tmp[i-1][j-1]+1 )
- 如果str1[i] != str2[j],则 tmp[i][j] = max( tmp[i-1][j], tmp[i][j-1] )
注意:
因为状态转移方程用到了上一行或者前一列的转态, 所以在初始化时, 给记录转态的tmp矩阵 第0行第0列进行了赋0操作,
真正字符串的转移状态从(1,1)开始到(str1.size(), str2.size())结束
而为了给tmp矩阵第0行第0列 赋 0 方便, 这里我直接初始化tmp 为全0阵
最后返回tmp[M][N],M、N为两个字符串的长度
举例:
序列s1 = { A,B,C,B,D,A,B}
序列s2 = { B,D,C,A,B,A}
最终结果{B C B A}
// 最长公共子序列
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main() {
string s1, s2;
while (cin >> s1 >> s2) {
int res = 0;
// 为了方便给tmp矩阵第0行0列赋0值,
// 初始化tmp 为全零矩阵
vector<vector<int>> tmp(s1.size() + 1, vector<int>(s2.size() + 1, 0));
for (int i = 1; i <= s1.size(); ++i) {
for (int j = 1; j <= s2.size(); ++j) {
if (s1[i - 1] == s2[j - 1]) {
tmp[i][j] = tmp[i - 1][j - 1] + 1;
}
else if (tmp[i - 1][j] > tmp[i][j - 1])
tmp[i][j] = tmp[i - 1][j];
else
tmp[i][j] = tmp[i][j - 1];
}
}
cout << tmp[s1.size()][s2.size()] << endl;
}
return 0;
}
如果需要输出最长子序列: 则对代码稍作修改, 添加一个 temp矩阵.
temp[i][j] 用来记录 tmp[i][j] 是通过哪个方向求得的.
// 最长公共子序列
#include<iostream>
#include<string>
#include<vector>
using namespace std;
void Construct(vector<vector<int>> temp, string s1, int i, int j) {
if (i == 0 || j == 0)
return;
if (temp[i][j] == 0) {
Construct(temp, s1, i - 1, j - 1);
cout << s1[i - 1];
}
else if (temp[i][j] == 1)
Construct(temp, s1, i - 1, j);
else
Construct(temp, s1, i, j - 1);
}
int main() {
string s1, s2;
while (cin >> s1 >> s2) {
int res = 0;
vector<vector<int>> tmp(s1.size() + 1, vector<int>(s2.size() + 1, 0));
vector<vector<int>> temp(s1.size() + 1, vector<int>(s2.size() + 1, 0));
for (int i = 1; i <= s1.size(); ++i) {
for (int j = 1; j <= s2.size(); ++j) {
if (s1[i - 1] == s2[j - 1]) {
tmp[i][j] = tmp[i - 1][j - 1] + 1;
temp[i][j] = 0;
}
else if (tmp[i - 1][j] > tmp[i][j - 1]) {
tmp[i][j] = tmp[i - 1][j];
temp[i][j] = 1;
}
else {
tmp[i][j] = tmp[i][j - 1];
temp[i][j] = -1;
}
}
}
Construct(temp, s1, s1.size(), s2.size());
}
return 0;
}