1312. Minimum-Insertion-Steps-to-Make-a-String-Palindrome

difficulty: Hard

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".

Example 4:

Input: s = "g"
Output: 0

Example 5:

Input: s = "no"
Output: 1

Constraints:

  • 1 <= s.length <= 500

  • All characters of s are lower case English letters.

Method One

class Solution {
    public int minInsertions(String s) {
        // 参见 1143 516 它 和 1143 516 是一样的题目
        // 1143 是两个 string 找 最长 subsequence 
        //
        // 对于 1312, 如果我们把这个 String 反过来
        // 比如 zzaz, 反过来是 zazz, 我们找到它最长的 subsequence 的长度 k = 3,
        // 那么我们就只需要插入 N - k = 1 个就可以让  zzaz 和 zazz 相同了。
        // 论证:
        // 一个 palindrome String 和 它的 reverse string 的 最长 common subsequence 肯定是他们自己。
        // 一个 String 和 它 reverse String 的 common subsequence 肯定是 回文 palindrome 的。
        // 剩下的字母我们都可以通过在对应位置复制一份实现回文。每添加一个字符,就能减少一个不回文的字符。
        // 假设一个 string p 是 palindrome. 令 p 分成两份 p = pa + pb;
        // 现在添加一个字符 a 构成新 String 是 pa + a + pb; 
        // 记pa,pb 的reverse 是 ap, bp. ap + bp = p;
        // 那么reverse String 是 bp + a + ap. 最长 subsequence 还是 p.
        // 为了消除 a, 那么就需要在对应位置加一个 a 就行了。
        
        int N = s.length();
        int[][] dp = new int[N + 1][N + 1];
        
        for(int i = 0;i < N; i++ ) {
            for(int j = 0; j < N; j++ ) {
                int end = N - 1 - j;
                if( s.charAt(i) == s.charAt(end) ) {
                    dp[i + 1][j + 1] = dp[i][j] + 1;
                }else {
                    dp[i + 1][j + 1] = Math.max(dp[i][j + 1], dp[i + 1][j] );
                }
            }
        }
        return N - dp[N][N];
    }
}

以上写的可读性比较差,当年还是年轻,我也不记得这是哪年写的题了。 对于516来说,最长回文子序列, 就是找该string和它的reverse string的 最长相同子序列 LCS。 这一点可以通过观察对称性来判断。假如某string无重复字符,那么反转就会反转全部的子序列,LCS只能1. 对于1312来说,需要insertion的数量就是字符的长度,减去该LCS。

为了更清楚的阐述这一点,我写了如下的 516 的代码。

class Solution {
    public int longestPalindromeSubseq(String s) {
        int N = s.length();
        int[][] LCS = new int[N + 1][N + 1];
        StringBuilder sb = new StringBuilder(s);
        String rs = sb.reverse().toString();
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (s.charAt(i) == rs.charAt(j)) {
                    LCS[i + 1][j + 1] = LCS[i][j] + 1;
                } else {
                    LCS[i + 1][j + 1] = Math.max(LCS[i + 1][j], LCS[i][j + 1]);
                }
            }
        }
        return LCS[N][N]; // 1312 返回的是 N - LCS[N][N];
    }
}

Last updated

Was this helpful?