添加最少的字符让字符串变成回文串(2)
题目描述
给定一个字符串str,再给定str的最长回文子序列字符串strlps, 请返回在添加字符最少的情况下,让str整体都是回文字符串的一种结果。进阶问题比原问题多了一个参数,请做到时间复杂度比原问题的实现低。
输入描述:
输出包含两行,第一行包含一个字符串代表 s t r ( 1 ≤ l e n g t h s t r ≤ 5000 ) str(1 \leq length_{str} \leq 5000) str(1≤lengthstr≤5000),第二行包含一个字符串,代表strips。
输出描述:
输出一行,代表返回的值。
示例1
输入
A1B21C
121
输出
AC1B2B1CA
说明
str=“A1B21C",strlps="121",返回“AC1B2B1CA”或者“CA1B2B1AC”,总之,只要是添加的字符数最少,只返回其中一种结果即可。
题解:
既然此题给了最长回文子序列,那么我们就要考虑用此子序列搞事情。最长回文子序列肯定出现在最终的回文串中,并且子序列左右部分没有相等的字符(不然会构成更长的回文子序列),并且最终的回文子串长度为:2*len(str)-len(strlps)。我们可以采用 “剥洋葱” 的方式去构造回文串:
- 在 str 左边找到等于 strlps 第一个字符的位置,设为 sl,在 str 右边找到等于 strlps 最后一个字符(也是第一个字符)的位置,设为 sr;
- 将 str[0…sl-1] + str[len-1…sr+1]复制到最终子串左半部分,str[sr+1…len-1] + str[sl-1…0]复制到最终子串右半部分,然后将 strlps 首字符复制到最终子串左右部分。
- 跳过 strlps 首尾字符,继续处理下一个字符,直到 strlps 处理完毕。
代码:
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 5001;
char s[N];
char t[N];
char ret[N << 1];
int main(void) {
scanf("%s", s);
scanf("%s", t);
int ls = strlen(s);
int lt = strlen(t);
int tot_len = (ls << 1) - lt;
int ss = 0, se = ls - 1;
int ts = 0, te = lt - 1;
int rs = 0, re = tot_len - 1;
while (ts <= te) {
while (s[ss] != t[ts]) {
ret[rs++] = s[ss];
ret[re--] = s[ss++];
}
while (s[se] != t[ts]) {
ret[rs++] = s[se];
ret[re--] = s[se--];
}
ret[rs++] = s[ss++];
ret[re--] = s[se--];
++ts, --te;
}
puts(ret);
return 0;
}