开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 31 天,点击查看活动详情
1312. 让字符串成为回文串的最少插入次数 - 力扣(Leetcode)
题目描述
给你一个字符串 s ,每一次操作你都可以在字符串的任意位置插入任意字符。
请你返回让 s 成为回文串的 最少操作次数 。
「回文串」是正读和反读都相同的字符串。
示例 1:
输入: s = "zzazz"
输出: 0
解释: 字符串 "zzazz" 已经是回文串了,所以不需要做任何插入操作。
示例 2:
输入: s = "mbadm"
输出: 2
解释: 字符串可变为 "mbdadbm" 或者 "mdbabdm" 。
示例 3:
输入: s = "leetcode"
输出: 5
解释: 插入 5 个字符后字符串变为 "leetcodocteel" 。
提示:
1 <= s.length <= 500s中所有字符都是小写字母。
题目分析
本题为线性DP的一道问题。
题目要求输出使当前字符串 成为最长回文字串的操作数,即求最长的回文子串的长度,操作数为字符串长度 。
我们知道,回文子串会有一个中心对称轴,沿轴向左向右字符依次相等。
于是,我们换一种思路,首先定义另一个字符串 为字符串 的逆串,即 ,并求取字符串 和 的最长公共子序列长度,这个值即为字符串 的最长公共子序列长度。
例如,,得到 ,最长公共子序列为 ,这也是字符串 的最长回文子串。
定义 表示 的前 个字符和 的前 个字符的最长公共子序列,最终的操作数便为 。
具体的求最长公共子序列的分析见上次题解。
Accept代码
题目来源于力扣,代码规范为力扣
class Solution {
int f[510][510];
public:
int minInsertions(string s) {
string sf = s;
reverse(s.begin(), s.end());
s = ' ' + s, sf = ' ' + sf;
int n = s.size();
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++)
{
f[i][j] = max(f[i - 1][j], f[i][j - 1]);
if (s[i] == sf[j]) f[i][j] = f[i - 1][j - 1] + 1;
}
return (n - f[n][n]);
}
};
#define N 510
int a[N], b[N], f[N][N];
int minInsertions(char * s){
int n = strlen(s);
for (int i = 1; i <= n; i ++)
{
a[i] = s[i - 1];
b[i] = s[n - i];
}
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++)
{
f[i][j] = f[i - 1][j] > f[i][j - 1] ? f[i - 1][j] : f[i][j - 1];
if (a[i] == b[j]) f[i][j] = f[i - 1][j - 1] + 1;
}
return n - f[n][n];
}