合并单词(公共子序列)
题目
合并 apple 和 peach 的最短长度, 结果为 appleach。
若有多个结果输出任意一个, 如 cranberry 和 boysenberry 可以输出 boysecranberry 或者 craboysenberry。
单词长度不超过100, 请使用优化做法。
输入包含多组数据, 以EOF为结尾。
input
apple peach
ananas banana
pear peach
output
appleach
bananas
pearch
思路
很显然的思路是找到两个单词最长公共子序列, 删去其在另一个单词的位置,然后拼接。
找到并保存最长公共子序列的内容参考这个
拼接似乎很麻烦, 不过可以直接在找最长序列的同时存下:
之前存内容时只存了 a[i] == b[j]
, 这里可以把 向左, 向上 转移的字符也存下。
注意最后可能没到 a[0],b[0]
需要加上剩余的字符。
代码
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdio>
#include <set>
using namespace std;
const int N = 1e3 + 10;
int f[N][N];
int main()
{
string a, b;
while (cin >> a >> b)
{
mem(f, 0);
a = "1" + a, b = "2" + b;
int n = a.size() - 1, m = b.size() - 1;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (a[i] == b[j])
f[i][j] = max(f[i][j], f[(i - 1)][(j - 1)] + 1);
else
f[i][j] = max(f[i][(j - 1)], f[(i - 1)][j]);
}
}
// 找最长公共子序列
string s;
int i = n, j = m;
while (i >= 1 && j >= 1)
{
if (a[i] == b[j])
s += b[j], i--, j--;
else if (f[i - 1][j] > f[i][j - 1])
s += a[i--];
else
s += b[j--];
}
while (i)
s += a[i--];
while (j)
s += b[j--];
reverse(all(s));
cout << s << endl;
string s;
}
return 0;
}