添加最少的字符让字符串变为回文字符串(1)
题目描述
给定一个字符串str,如果可以在str的任意位置添加字符,请返回在添加字符最少的情况下,让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)。
输出描述:
输出一行,代表返回的字符串。
示例1
输入
ABA
输出
ABA
示例2
输入
AB
输出
ABA
备注:
时间复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度 O ( n 2 ) O(n^2) O(n2)。
题解:
动态规划,设 F[i, j] 表示子串 s[i…j] 最少添加几个字符可以使得 s[i…j] 整体是回文串,F[i, j] 有下面三种情况:
- 只有一个字符,那么明显的:F[i, j] = 0;
- 只有两个字符,若两个字符相等,则 F[i, j] = 0;否则的话,只需要添加一个字符,则 F[i, j] = 1;
- 多于两个字符,若 s[i] == s[j] ,则 F[i, j] = F[i+1, j-1] ;否则的话,F[i, j] = min{F[i+1, j], F[i, j-1]} + 1。
在输出时,只需要根据动态规划表还原即可。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 5001;
char s[N];
int f[N][N];
char ret[N << 1];
int main(void) {
scanf("%s", s);
int len = strlen(s);
for (int i = 0; i < len - 1; ++i)
f[i][i + 1] = (s[i] != s[i + 1]);
for (int i = len - 2; i >= 0; --i) {
for (int j = i + 2; j < len; ++j) {
if (s[i] == s[j]) f[i][j] = f[i + 1][j - 1];
else f[i][j] = min(f[i + 1][j], f[i][j - 1]) + 1;
}
}
int i = 0, j = len - 1;
int tot_len = len + f[0][len - 1];
int l = 0, r = tot_len - 1;
while (i <= j) {
if (s[i] == s[j]) {
ret[l++] = s[i++];
ret[r--] = s[j--];
} else if (f[i + 1][j] < f[i][j - 1]) {
ret[l++] = ret[r--] = s[i++];
} else {
ret[l++] = ret[r--] = s[j--];
}
}
puts(ret);
return 0;
}