`

Leetcode - Palindrome Partition II

 
阅读更多

Given a string s, partition s such that every substring of the partition is a palindrome.

Return the minimum cuts needed for a palindrome partitioning of s.

For example, given s = "aab",
Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.

[balabala] 这道题目的直接思路是利用Palindrome Partition的思路,利用isPalin[i][j] 递归求解,算法复杂度是O(N^N),果断超时。进一步优化,保存一个cut[][]数组,其中cut[i][j] 表示s[i,j] 对应子串的min cuts,递推式见代码,时间复杂度是O(N^3),仍然超时。最终O(N^2)的版本是一年前网上找的答案,未记录出处。不知道大神脑袋瓜怎么运转的,我能理解正确性,但想不通如何得到这种优化思路的。method3是直接参考的,method4我就反了个求解顺序,原理同method3一样,若是自己想估计会写成method4的样子。貌似自己该多练习逆向思考。method3 和 method4中dp数组多开了一个,并且每个元素比真实值多1,这是个编码技巧,可以避免for循环中判断边界条件,一开始自己不能体会作者用意,dp数组不多开元素保持真实值,会得到wrong answer,带进代码debug下就能理解了。

 

public class Solution {
    // Method 5: 重做时自己的写法
    public int minCut(String s) {
        if (s == null || s.length() == 0)
            return 0;
        int n = s.length();
        boolean[][] isPalin = new boolean[n][n];
        for (int i = 0; i < n - 1; i++) {
            isPalin[i][i] = true;
            isPalin[i][i + 1] = s.charAt(i) == s.charAt(i + 1);
        }
        isPalin[n - 1][n - 1] = true;
        for (int l = 3; l <= n; l++) {
            for (int i = 0; i + l <= n; i++) {
                int j = i + l - 1;
                isPalin[i][j] = s.charAt(i) == s.charAt(j) && isPalin[i + 1][j - 1];
            }
        }
        if (isPalin[0][n - 1])
            return 0;
        int[] dp = new int[n];
        for (int i = 0; i < n; i++) {
            if (!isPalin[0][i]) {
                dp[i] = n;
                for (int j = 0; j < i; j++) {
                    if (isPalin[j + 1][i])
                        dp[i] = Math.min(dp[i], dp[j] + 1);
                }
            }
        }
        return dp[n - 1];
    }
    // dp[i]:s.substring(0, i)需要的min cuts
    public int minCut(String s) {
        if (s == null || s.length() == 0)
            return 0;
        int n = s.length();
        boolean[][] isPalin = new boolean[n][n];
        int[] dp = new int[n + 1];
        for (int i = 1; i <= n; i++)
            dp[i] = i;
        for (int i = 0; i < n; i++) {
            for (int j = i; j >= 0; j--) {
                if (s.charAt(i) == s.charAt(j) && (i - j < 2 || isPalin[i - 1][j + 1])) {
                    isPalin[i][j] = true;
                    dp[i + 1] = Math.min(dp[i + 1], dp[j] + 1);
                }
            }
        }
        return dp[n] - 1;
    }
    
    // O(N^2)
    // dp[i]: s.substring(i, n) 需要的min cuts
    // dp[i] = min(dp[j] + 1), j > i
    // dp数组多加个元素的好处是dp[i] = Math.min(dp[i], dp[j + 1] + 1); 这一行不需要对下标进行检查
    public int minCut3(String s) {
        if (s == null || s.length() == 0)
            return 0;
        int n = s.length();
        boolean[][] isPalin = new boolean[n][n];
        int[] dp = new int[n + 1];
        for (int i = 0; i <= n; i++)
            dp[i] = n - i;
        for (int i = n - 1; i >= 0; i--) {
            for (int j = i; j < n; j++) {
                if (s.charAt(i) == s.charAt(j) && (j - i < 2 || isPalin[i + 1][j - 1])) {
                    isPalin[i][j] = true;
                    dp[i] = Math.min(dp[i], dp[j + 1] + 1);
                }
            }
        }
        return dp[0] - 1;
    }
    
    // O(N^3)
    public int minCut2(String s) {
        if (s == null || s.length() == 0)
            return 0;
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        int[][] cut = new int[n][n];
        for (int i = 0; i < n; i++)
            dp[i][i] = true;
        for (int i = 0; i < n - 1; i++) {
            if (s.charAt(i) == s.charAt(i + 1)) {
                dp[i][i + 1] = true;
                cut[i][i + 1] = 0;
            } else {
                dp[i][i + 1] = false;
                cut[i][i + 1] = 1;
            }
        }
        
        int j = 0;
        for (int len = 3; len <= n; len++) {
            for (int i = 0; i <= n - len; i++) {
                j = i + len - 1;
                dp[i][j] = s.charAt(i) == s.charAt(j) ? dp[i + 1][j - 1] : false;
                if (dp[i][j]) {
                    cut[i][j] = 0;
                } else {
                    cut[i][j] = n;
                    for (int k = i; k < j; k++) {
                        cut[i][j] = Math.min(cut[i][j], cut[i][k] + cut[k + 1][j] + 1);
                    }
                }
            }
        }
        return cut[0][n - 1];
    }
    
    //O(N!)
    public int minCut1(String s) {
        if (s == null || s.length() == 0)
            return 0;
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        for (int i = 0; i < n; i++)
            dp[i][i] = true;
        for (int i = 0; i < n - 1; i++)
            dp[i][i + 1] = s.charAt(i) == s.charAt(i + 1) ? true : false;
        int j = 0;
        for (int len = 3; len <= n; len++) {
            for (int i = 0; i <= n - len; i++) {
                j = i + len - 1;
                dp[i][j] = s.charAt(i) == s.charAt(j) ? dp[i + 1][j - 1] : false;
            }
        }
        return getMinCut(s, 0, dp);
    }
    
    private int getMinCut (String s, int start, boolean[][] dp) {
        int n = s.length();
        if (start == n || dp[start][n - 1])
            return 0;
        
        int min = n - start;
        for (int i = start; i < n - 1; i++) {
            if (dp[start][i]) {
                min = Math.min(min, getMinCut(s, i + 1, dp) + 1);
            }
        }
        return min;
    }
}

 

 

 

 

分享到:
评论

相关推荐

    LeetCode最全代码

    137 | [Single Number II](https://leetcode.com/problems/single-number-ii/) | [C++](./C++/single-number-ii.cpp) [Python](./Python/single-number-ii.py) | _O(n)_ | _O(1)_ | Medium ||| 190 | [Reverse Bits]...

    leetcode中325题python-leetcode:leetcode

    partition-list 92 反转链表 II reverse-linked-list-ii(Reverse a Sub-list) 141 环形链表 linked-list-cycle 142 环形链表 II linked-list-cycle-ii 143 重排链表 reorder-list 148 排序链表 sort-list 234 回文...

    算法刷题笔记leetcode/lintcode

    - Valid Palindrome(回文字符串验证) - Longest Palindromic Substring(最长回文子串) - Space Replacement(URL化) - Wildcard Matching(通配符匹配) - Length of Last Word(最后一个单词的长度) - ...

    Leetcode题目+解析+思路+答案.pdf

    - **Palindrome Number**:判断一个数字是否是回文数。 - **Search a 2D Matrix**:在二维矩阵中搜索目标值。 - **Search for a Range**:在一个排序数组中查找目标值的第一个和最后一个位置。 - **Search ...

    Leetcode答案(c++版)

    **1.16 Palindrome LinkedList (234)** - **问题描述**:判断链表是否为回文结构。 - **解题思路**: - 使用快慢指针找到链表的中间位置。 - 反转后半部分链表,然后比较前后两部分是否完全相同。 **1.17 Odd ...

    python-leetcode面试题解之第131题分割回文串-题解.zip

    def partition(s): def is_palindrome(s): return s == s[::-1] n = len(s) dp = [[False] * n for _ in range(n)] ans = [] def backtrack(start): if start == n: ans.append(''.join(parts)) return...

    LeetCode练习答案

    - **基本计算器II(Basic Calculator II)**: 给定一个字符串表达式,实现一个基本计算器来计算并返回结果。 以上总结仅为部分知识点的简述,对于每一个具体的算法问题,都有其独特的解决思路和技巧,建议深入研究每...

Global site tag (gtag.js) - Google Analytics