Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LeetCode] 1312. Minimum Insertion Steps to Make a String Palindrome #1312

Open
grandyang opened this issue May 30, 2019 · 0 comments
Open

Comments

@grandyang
Copy link
Owner

grandyang commented May 30, 2019

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 同步地址:

#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 changed the title [LeetCode] 1312. Missing Problem [LeetCode] 1312. Minimum Insertion Steps to Make a String Palindrome Nov 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant