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

&#x20;

**Example 1:**

<pre><code><strong>Input: s = "zzazz"
</strong><strong>Output: 0
</strong><strong>Explanation: The string "zzazz" is already palindrome we don't need any insertions.
</strong></code></pre>

**Example 2:**

<pre><code><strong>Input: s = "mbadm"
</strong><strong>Output: 2
</strong><strong>Explanation: String can be "mbdadbm" or "mdbabdm".
</strong></code></pre>

**Example 3:**

<pre><code><strong>Input: s = "leetcode"
</strong><strong>Output: 5
</strong><strong>Explanation: Inserting 5 characters the string becomes "leetcodocteel".
</strong></code></pre>

**Example 4:**

<pre><code><strong>Input: s = "g"
</strong><strong>Output: 0
</strong></code></pre>

**Example 5:**

<pre><code><strong>Input: s = "no"
</strong><strong>Output: 1
</strong></code></pre>

&#x20;

**Constraints:**

* `1 <= s.length <= 500`
* All characters of `s` are lower case English letters.

## Method One

```Java
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 的代码。

```java
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];
    }
}
```
