1312. Minimum Insertion Steps to Make a String Palindrome

Given a string s. In one step you can insert any character at any index of the string.

Return  the minimum number of steps  to make s palindrome.

A Palindrome String is one that reads the same backward as well as forward.

Example 1:

Input: s = "zzazz"
Output: 0
Explanation: The string "zzazz" is already palindrome we don't need any insertions.

Example 2:

Input: s = "mbadm"
Output: 2
Explanation: String can be "mbdadbm" or "mdbabdm".

Example 3:

Input: s = "leetcode"
Output: 5
Explanation: Inserting 5 characters the string becomes "leetcodocteel".

Constraints:

  • 1 <= s.length <= 500
  • s consists of lowercase English letters.

这道题说是给了一个字符串s,可以在任意位置加入任意字符,问可以使其变为回文串的最少添加字符的个数是多少。对于回文串,想必大家都不陌生,就是正读反读都一样的字符串,比如 noon, bob 等等。这里给定的字符串如果本身就是个回文串,则就不需要加入字符了,比如例子1,若不是回文串,就需要在适当的位置加入字符,使其变为回文串,比如例子2。对于字符串求极值的问题,经验常识告诉我们基本上都是用动态规划 Dynamic Programming 来做,这里如果直接去想到底在哪个位置上加字符才能使其变为回文串,感觉不太好入手,因为可以加的方法太多了,总不能遍历所有的情况吧。

这里需要转变个思路来做,可以说这个思路转变是这道题的精髓所在,在直接给出答案之前,让我们先来做个简单的分析:由于可以在任意位置加上任意个字符,所以只要把原字符串反转一下,直接加在后面,就一定是一个回文串,但是这种加法不一定用的字符最少,其实应该尽可能去利用原字符串里具有的一些子序列回文串,比如例子2的 mbadm,如果利用其子序列回文串 mam 的话,实际上只需要增添b和d两个字符就可以构成整体的回文串了。所以子序列回文串越长,需要添加的字符就越少,于是乎问题就转换为了求最长的子序列回文串的长度,就变成了之前的那道 Longest Palindromic Subsequence

这里定义一个二维的 dp 数组,其中 dp[i][j] 表示原字符串 [i, j] 范围内的子串中最长子序列回文串的长度。接下来就要找状态转移方程了,先从最简单的开始分析,若子串长度为1,则其一定是回文串,即 dp[i][i] 为1,然后以此为中心,分别往两边扩展,比较两边相对应的字符是否相同,对于一个区间 [i, j],两边的字符分别为 s[i] 和 s[j],中间的部分是 [i+1, j-1],假设中间子串中的最长子序列回文串的长度已经求得了,为 dp[i+1][j-1],若此时 s[i] 和 s[j] 相等的话,说明子序列回文串的长度又增加了2,则可以用 dp[i+1][j-1] + 2 来更新 dp[i][j],若 s[i] 和 s[j] 不相等的话,则可以比较区间 [i+1, j] 和 [i, j-1] 中谁的子序列回文串更长,用较长的长度来更新 dp[i][j]。分析到这里,代码就不难写了吧,最终字符串s的最长子序列回文串的长度为 dp[0][n-1],只要返回 n - dp[0][n-1] 即使要增加的字符个数了,参见代码如下:

class Solution {
public:
    int minInsertions(string s) {
        int res = 0, n = s.size();
        vector<vector<int>> dp(n, vector<int>(n));
        for (int i = n - 1; i >= 0; --i) {
            dp[i][i] = 1;
            for (int j = i + 1; j < n; ++j) {
                dp[i][j] = (s[i] == s[j]) ? (dp[i + 1][j - 1] + 2) : max(dp[i + 1][j], dp[i][j - 1]);
            }
        }
        return n - dp[0][n - 1];
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1312

类似题目:

Longest Palindromic Subsequence

Minimum Number of Moves to Make Palindrome

参考资料:

https://leetcode.com/problems/minimum-insertion-steps-to-make-a-string-palindrome/

https://leetcode.com/problems/minimum-insertion-steps-to-make-a-string-palindrome/discuss/470706/JavaC%2B%2BPython-Longest-Common-Sequence

https://leetcode.com/problems/minimum-insertion-steps-to-make-a-string-palindrome/discuss/470684/C%2B%2B-Simple-DP-(Memoization)-and-Bottom-up-with-O(n)-Space

LeetCode All in One 题目讲解汇总(持续更新中…)

(欢迎加入博主的知识星球,博主将及时答疑解惑,并分享刷题经验与总结,快快加入吧~)

知识星球 喜欢请点赞,疼爱请打赏❤️.

微信打赏

|

Venmo 打赏


—|—


转载请注明来源于 Grandyang 的博客 (grandyang.com),欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 grandyang@qq.com

💰


微信打赏


Venmo 打赏

(欢迎加入博主的知识星球,博主将及时答疑解惑,并分享刷题经验与总结,试运营期间前五十位可享受半价优惠~)

×

Help us with donation