Palindrome Partitioning II @LeetCode

LeetCode 原题链接 :

https://oj.leetcode.com/problems/palindrome-partitioning-ii/


对于给定字符串,求最少需要几次划分,能够将字符串划分为若干子串,每个子串都是一个回文串。如abaab,需要至少2次划分,将字符串划分为:aba|a|b,每个部分均为回文串。


经典的DP题目。

我们可以分解为DP问题:

参考文章: http://fisherlei.blogspot.com/2013/03/leetcode-palindrome-partitioning-ii.html


[Thoughts]
凡是求最优解的,一般都是走DP的路线。这一题也不例外。首先求dp函数,

定义函数
D[i,n] = 区间[i,n]之间最小的cut数,n为字符串长度

 a   b   a   b   b   b   a   b   b   a   b   a
                     i                                  n
如果现在求[i,n]之间的最优解?应该是多少?简单看一看,至少有下面一个解


 a   b   a   b   b   b   a   b   b   a   b   a
                     i                   j   j+1     n

此时  D[i,n] = min(D[i, j] + D[j+1,n])  i<=j
D[i] = 区间[i,n]之间最小的cut数,n为字符串长度, 则,

D[i] = min(1+D[j+1] )    i<=j

有个转移函数之后,一个问题出现了,就是如何判断[i,j]是否是回文?每次都从i到j比较一遍?太浪费了,这里也是一个DP问题。
定义函数
P[i][j] = true if [i,j]为回文

那么
P[i][j] = str[i] == str[j] && P[i+1][j-1];


public class Solution {
    public int minCut(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        
        int len = s.length();
        int[] D = new int[len];
        
        boolean[][] isPalid = new boolean[len][len];
        
        for (int i = len - 1; i >= 0; i--) {
            // the worst case is divide the word one by one.
            D[i] = len - 1 -i;
            for (int j = i; j <= len - 1; j++) {
                // init it to be false;
                isPalid[i][j] = false;
                
                if (s.charAt(i) == s.charAt(j) && (j - i <= 1 || isPalid[i + 1][j - 1])) {
                    isPalid[i][j] = true;
                    if (j == len - 1) {
                        D[i] = 0;
                    } else {
                        // 如果前半部分是回文,那么我们可以分解为第一个回文 + 后半部分的最小分割数
                        D[i] = Math.min(D[i], D[j + 1] + 1);
                    }
                }
            }
        }
        
        return D[0];
    }
}

你可能感兴趣的:(LeetCode)