zoukankan      html  css  js  c++  java
  • 132. Palindrome Partitioning 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.

    Example:

    Input: "aab"
    Output: 1
    Explanation: The palindrome partitioning ["aa","b"] could be produced using 1 cut.
    
     

    Approach #1: DP. [C++]

    class Solution {
    public:
        int minCut(string s) {
            int len = s.length();
            if (len == 0) return 0;
            vector<vector<bool>> isPanlindrome(len+1, vector<bool>(len+1, false));
            vector<int> cuts(len);
            
            for (int i = 0; i < len; ++i) {
                int minn = i;
                for (int j = 0; j <= i; ++j) {
                    if (s[j] == s[i] && (i-j < 2 || isPanlindrome[j+1][i-1])) {
                        isPanlindrome[j][i] = true;
                        minn = j == 0 ? 0 : min(minn, cuts[j-1] + 1);
                    }
                }
                cuts[i] = minn;
            }
            
            return cuts[len-1];
        }
    };
    

      

    Analysis:

    https://leetcode.com/problems/palindrome-partitioning-ii/discuss/42213/Easiest-Java-DP-Solution-(97.36)

    isPalindrome[i][j] represent the characters from i to j is palindrome.

    cuts[i] represent the index from 0 to i need to cut how many time so that it can be satify the condition.


    2021-04-16

    给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。

    返回符合要求的 最少分割次数 。

    示例 1:

    输入:s = "aab"
    输出:1
    解释:只需一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。
    示例 2:

    输入:s = "a"
    输出:0
    示例 3:

    输入:s = "ab"
    输出:1
     

    提示:

    1 <= s.length <= 2000
    s 仅由小写英文字母组成

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/palindrome-partitioning-ii
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    题意:

      这是一道经典的DP题,可以采用二维DP(本题会超时),也可以进一步优化从而使DP降到一维。因为二维DP相对容易理解些,所以我们先从二维DP来计算。

    题解:

      palindromeTable[i][j]:用来表示s[i][j]是否是一个回文字符串,它有三种状态:

    • length = 1时:
      • palindromeTable[i][i] = true  
    • length = 2时:
      • if s[i] == s[i+1]: palindromeTable[i][j] = true
      • else: palindromeTable[i][j] = false
    • length > 2时:
      • if s[i] == s[j]: palindromeTable[i][j] = palindromeTable[i-1][j-1]
      • else: palindromeTable[i][j] = false  

      dpTable[i][j]:用来表示将s[i][j]拆分成都是回文的子串所需要的最少拆分次数,它也是有三种状态:

    • length = 1时:
      • dpTable[i][i] = 0    
    • length = 2时:
      • if s[i] == s[i+1]: dpTable[i][i+1] = 0
      • else: dpTable[i][i+1] = 1 
    • length > 2时:
      • if palindromeTable[i][j] = true: dpTable[i][j] = 0
      • else: dpTable[i][j] = min(dpTable[i][j], dpTable[i][k] + dpTable[k+1][j] + 1),其中i < k < j 

      最后的结果就是DPTable[0][len-1]。

    代码:

    #include <iostream>
    #include <string>
    #include <vector>
    
    using namespace std;
    
    const int inf = 0x7fffffff;
    
    void creatPalindromeTable(const string& s, vector<vector<bool> >& table) {
        int len = s.length();
        // length = 1
        for (int i = 0; i < len; ++i) table[i][i] = true;
        // length = 2
        for (int i = 0; i < len - 1; ++i)
            if (s[i] == s[i + 1]) table[i][i + 1] = true;
        // length > 2
        for (int i = 3; i <= len; ++i) {
            for (int j = 0; j + i <= len; ++j) {
                if (s[j] == s[j + i - 1]) {
                    table[j][j + i - 1] = table[j + 1][j + i - 2];
                }
            }
        }
    }
    
    void creatDpTable(const string& s, vector<vector<int> >& dpTable) {
        int len = s.length();
        vector<vector<bool> > palindromeTable(len, vector<bool>(len, false));
        creatPalindromeTable(s, palindromeTable);
        // length = 1
        for (int i = 0; i < len; ++i) dpTable[i][i] = 0;
        // length = 2
        for (int i = 0; i < len - 1; ++i)
            if (s[i] == s[i + 1])
                dpTable[i][i + 1] = 0;
            else
                dpTable[i][i + 1] = 1;
        // length > 2
        for (int i = 3; i <= len; ++i) {
            for (int j = 0; j + i <= len; ++j) {
                if (palindromeTable[j][j + i - 1])
                    dpTable[j][j + i - 1] = 0;
                else
                    for (int k = j; k < j + i - 1; ++k)
                        dpTable[j][j + i - 1] =
                            min(dpTable[j][j + i - 1],
                                dpTable[j][k] + dpTable[k + 1][j + i - 1] + 1);
            }
        }
    }
    
    int main() {
        string s;
        cin >> s;
        int len = s.length();
        vector<vector<int> > dpTable(len, vector<int>(len, inf));
        creatDpTable(s, dpTable);
        cout << dpTable[0][len - 1] << endl;
        return 0;
    }

      这样做提交的时候会报超时,因为这道题的最后结果只需要dpTable就可以了,所以我们可以想办法对dpTable进行降维,使dpTable默认从0开始dpTable[i]即表示dpTable[0][i]。这样的话就可以把时间复杂度从O(n^3)降到O(n^2)。

      dpTable[i]:代表从0到i所需的最小分割次数,共有两种状态。

    • if palindromeTable[0][i] = true: dpTable[i] = 0
    • else : dpTable[i] = min(dpTable[i], dpTable[j]+1), 其中 0 < j < i。  

    代码:

    #include <iostream>
    #include <string>
    #include <vector>
    
    using namespace std;
    
    const int inf = 0x7fffffff;
    
    void creatPalindromeTable(const string& s, vector<vector<bool> >& table) {
        int len = s.length();
        // length = 1
        for (int i = 0; i < len; ++i) table[i][i] = true;
        // length = 2
        for (int i = 0; i < len - 1; ++i)
            if (s[i] == s[i + 1]) table[i][i + 1] = true;
        // length > 2
        for (int i = 3; i <= len; ++i) {
            for (int j = 0; j + i <= len; ++j) {
                if (s[j] == s[j + i - 1]) {
                    table[j][j + i - 1] = table[j + 1][j + i - 2];
                }
            }
        }
    }
    
    void creatDpTable(const string& s, vector<int>& dpTable) {
        int len = s.length();
        vector<vector<bool> > palindromeTable(len, vector<bool>(len, false));
        creatPalindromeTable(s, palindromeTable);
    
        for (int i = 0; i < len; ++i) {
            if (palindromeTable[0][i])
                dpTable[i] = 0;
            else {
                for (int j = 0; j < i; ++j) {
                    if (palindromeTable[j + 1][i])
                        dpTable[i] = min(dpTable[i], dpTable[j] + 1);
                }
            }
        }
    }
    
    int main() {
        string s;
        cin >> s;
        int len = s.length();
        vector<int> dpTable(len, inf);
        creatDpTable(s, dpTable);
        cout << dpTable[len - 1] << endl;
        return 0;
    }
    永远渴望,大智若愚(stay hungry, stay foolish)
  • 相关阅读:
    xml解析
    xml基础
    对象的深浅克隆
    批处理文件(bat)
    贪吃蛇逻辑代码
    排序算法
    tcp,第一个例子,客户端,服务端
    网络编程三要素
    装饰者模式
    工作中遇到的问题
  • 原文地址:https://www.cnblogs.com/h-hkai/p/10367441.html
Copyright © 2011-2022 走看看