【回文串5 重点+动态规划】LeetCode 132. Palindrome Partitioning II

LeetCode 132. Palindrome Partitioning II

Solution1:我的答案1
直接模仿131那道题的DFS解法,找其中size最小的。果不其然,因为超时只能部分AC。代码如下,仅供记录:

class Solution {
public:
    int minCut(string s) {
        vector<string> temp;
        vector<string> res;
        PalinDFS(s, 0, temp, res);
        return res.size() - 1;
    }

    void PalinDFS (string str, int start, vector<string> &temp, vector<string> &res) {
        if (start == str.size()) {
            if (res.size() == 0 || res.size() > temp.size())
                res = temp;
            return;
        } 
        for (int i = start; i < str.size(); i++) {
            if (isPalin(str, start, i)) {
                temp.push_back(str.substr(start, i - start + 1));
                PalinDFS(str, i + 1, temp, res);
                temp.pop_back();
            }
        }
    }

    bool isPalin(string str, int begin, int end) { //[begin, end]是[闭,闭]区间
        int left = begin, right = end;
        while (left < right) {
            if (str[left] != str[right])
                return false;
            else {
                left++;right--;
            }
        }
        return true;
    }
};

Solution2:
参考网址:https://blog.csdn.net/jingsuwen1/article/details/51934277
解题思路:动态规划问题。
dp[i]表示子串[0, i]的最小回文切割,则最优解在dp[s.length-1]中。[0, i]的子串中包括了i+1个字符。
分几种情况:
1.初始化:当字串s[0:i] (包括i位置的字符)是回文串时,dp[i] = 0(表示不需要分割);否则,dp[i] = i(表示至多分割i次);
2.对于任意大于1的i,如果s[j:i]( 1 =< j <= i,即遍历i之前的每个子串)是回文时,dp[i] = min(dp[i], dp[j-1]+1);
(注:j不用取0是因为若j == 0,则又表示判断(0,i))。
相对容易理解的动态规划方法。

class Solution {
public:
    int minCut(string s) {
        if (s.size() == 0) return 0;
        //dp[i]存放以i位置字符结尾的字符串的最小切割数,即所求为dp[s.size() - 1]
        int dp[s.size()];
        dp[0] = 0;//单个字符,无需切割
        for(int i = 0; i < s.size(); i++) {
            //dp[i]赋初值
            dp[i] = isPalin(s, 0, i)? 0 : i;
            //1 =< j <= i子串回文判定
            for (int j = i; j >= 1; j--) {
                if (isPalin(s, j, i))
                    dp[i] = min(dp[i], dp[j-1] + 1);
            }
        }
        return dp[s.size() - 1];
    }

    bool isPalin(string &str, int begin, int end) {
        while (begin < end) {
            if (str[begin] != str[end])
                return false;
            else 
                begin++;end--;
        }
        return true;
    }
};

//20180718日更新,DP算法真厉害啊!
class Solution {
public:
    int minCut(string s) {
        if (s.size() <= 1) return 0;
        int dp[s.size()];
        for (int i = 0; i < s.size(); i++) {
            dp[i] = isPalin(s, 0, i) == 1? 0:i;
            for (int j = 1; j <= i; j++) {
                if (isPalin(s, j, i)) {
                    dp[i] = min(dp[i], dp[j-1] + 1);
                }
            }
        }
        return dp[s.size() - 1];
    }

    int isPalin(string& str, int begin, int end) {
        while (begin < end) {
            if (str[begin] != str[end])
               return 0;
            else {
                begin++;
                end--;
            }
        }
        return 1;
    }
};

Solution3:更优化的动态规划方法
参考网址:
http://www.cnblogs.com/grandyang/p/4271456.html
这道题是让找到把原字符串拆分成回文串的最小切割数,需要用动态规划Dynamic Programming来做,使用DP的核心是在于找出递推公式,之前有道地牢游戏Dungeon Game的题也是需要用DP来做,而那道题是二维DP来解,这道题由于只是拆分一个字符串,需要一个一维的递推公式,我们还是从后往前推,递推公式为:dp[i] = min(dp[i], 1+dp[j+1] ) i<=j

//在20180719搞懂了。。。
class Solution {
public:
    int minCut(string s) {
        int len = s.size();
        bool P[len][len];
        int dp[len + 1];
        for (int i = 0; i <= len; ++i) {
            //之所以要初始化dp[len] = -1
            //是为了当 j + 1 == len时计算用
            dp[i] = len - i - 1;
        }
        for (int i = 0; i < len; ++i) {
            for (int j = 0; j < len; ++j) {
                if (i == j) 
                    P[i][j] = true;
                else
                    P[i][j] = false;
            }
        }
        for (int i = len - 1; i >= 0; --i) {
            for (int j = i; j < len; ++j) {
                //更新p[i][j]时要用到i + 1和j - 1,故i要从大到小遍历,j要从小到大遍历
                if (s[i] == s[j] && (j - i <= 1 || P[i + 1][j - 1])) {
                    P[i][j] = true;
                    //dp[i]表示从s[i, s.size()-1]部分(闭闭区间)字符串的最小分割数
                    dp[i] = min(dp[i], dp[j + 1] + 1);
                }
            }
        }
        return dp[0];
    }
};

你可能感兴趣的:(LeetCode练习题)