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.

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

思路:第一种按照DFS搜索的方式,如果有了更小的切分,更新ans,最后输出ans,这样做直接TLE.

第二种思路,就应该考虑DP,DP[i]代表前i个元素的最小切分,那么DP[i] = min{ 1 + DP[j], (j+1 .. i 是Palindrome)} #不要只是想DP[i-1] 这种思路中复杂度是O(n^3), i,j 以及j+1..i判断是否是Palindrome. 依然TLE

第三种思路:对于上边的进行如何进行优化,到O(n^2) .那么对于回文来说,也可以继续DP. dp[i,j] = (s[i] == s[j] && dp[i+1,j-1]) 这个地方很有意思,比如:"abbab" 当看i=3 a的时候,判断[abba]是回文的时候,bb是否是回文已经判断过了,只要用dp寸下来就可以了。用了Memorize的技术,判断Palindrome就是O(1)了,整体复杂度优化到了O(n^2).题目里面的话,其实就是dp[j+1,i] = s[j+1] == s[j] && dp[j+2,i-1].

class Solution {
    public:
        int ans;
        vector<string> ans_v;
        
        bool IsPalindrome(const string & s){
            int i = 0; 
            int j = s.size() -1;
            //这里之前有一个bug,while(i != j) 比如 bb的情况,一下子 i = 1, j = 0, 然后就会越界访问 core dump
            while(i < j){
                if (s.at(i) == s.at(j)){
                    i++;
                    j--;
                }else{
                    return false;
                }
            }
            return true;
        }
        //这里dfs的意思是说从start的位置出发,找最近的回文串,然后继续递归
        // abbab-> 'a' 'b' 'b' 'a' 'b' path  OK
        // abbab-> 'a' 'b'             退栈直到 path
        // abbab-> 'a' 'b'  'bab'      path  OK
        // abbab-> 'a' 'bb' 'a' 'b'    path  OK
        // abbab-> ''                  path --> 一直退栈
        // abbab-> 'abba' 'b'          path  OK
        
        //如果是显式的给出图
        /*                  root
                         /         \
                           a           abba
                      /  \            \
                     b   'bb'          'b'
                    /  \    \           \
                   b   'bab' 'a'         OK
                  /       \    \
                 a         OK   'b'
                /                 \
               b                   OK
              /
             OK
            
            一目了然,你可以理解为图的DFS,也可以理解为树的DFS,Path就是记录路径的。
            因为本质是一棵树,不会重复访问,也不需要VISIT数组
            for循环本质是判断当前节点下有多少领接的边
            
            以后对于这种题目,先写出表达式tree或者graph,然后再去遍历
        */
        void dfs(string s, int start, vector<string> & path){
            if (start == s.size()){
                ans = ans > path.size() -1 ? path.size() -1 : ans;
                return;
            }
            for(int i = start + 1; i <= s.size(); i++){ //确定当前start位置出发的回文串
                string sub_s = s.substr(start,i - start);
                //cout << "start: "<<start<<" i: "<<i<<" sub_s: " << sub_s << "\n";
                if (IsPalindrome(sub_s)){
                    //cout << "here: " << sub_s << "\n";
                    path.push_back(sub_s);
                    dfs(s,i,path);
                    path.resize(path.size() -1);
                }
            }
        }
        int minCut(string s) {
            ans = 1<<30;
            ans_v.clear();
            dfs(s,0,ans_v);
            return ans;                 
        }
};
class Solution {
public: 
        bool IsPalindrome(const string & s){
            int i = 0; 
            int j = s.size() -1;
            //这里之前有一个bug,while(i != j) 比如 bb的情况,一下子 i = 1, j = 0, 然后就会越界访问 core dump
            while(i < j){
                if (s.at(i) == s.at(j)){
                    i++;
                    j--;
                }else{
                    return false;
                }
            }
            return true;
        }    
        int minCut(string s) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (s.size() == 0){
            return 0;
        }
        //DP[i] = min{ 1+ DP[j]} "j+1..i" is palindrome
        int * dp = new int[s.size()];
        dp[0] = 0;
        for(int i = 1; i < s.size(); i++){
            dp[i] = i;
            for(int j = i -1; j >= -1; j--){
                string sub_s = s.substr(j+1,i - j);                
                if (IsPalindrome(sub_s)){
                    //这里刚开始有一个BUG, min(dp[i],dp[j]) + 1 会导致每次都加1,其实是要求 min{DP[j] + 1}
                    dp[i] = j >=0 ? min(dp[i],dp[j] + 1) : 0;
                }    
            }
        }
        int ans = dp[s.size() -1];
        delete []dp;
        return ans;
    }
};
class Solution {
public: 
        bool IsPalindrome(const string & s){
            int i = 0; 
            int j = s.size() -1;
            //这里之前有一个bug,while(i != j) 比如 bb的情况,一下子 i = 1, j = 0, 然后就会越界访问 core dump
            while(i < j){
                if (s.at(i) == s.at(j)){
                    i++;
                    j--;
                }else{
                    return false;
                }
            }
            return true;
        }    
        int minCut(string s) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (s.size() == 0){
            return 0;
        }
        //DP[i] = min{ 1+ DP[j]} "j+1..i" is palindrome
        int * dp = new int[s.size()];
        //先写一个O(n^2)空间复杂度的版本
        int ** pl = new int*[s.size()];
        for(size_t i = 0; i < s.size(); i++){
            pl[i] = new int[s.size()];
            pl[i][i] = 1;
        }
        dp[0] = 0;

        for(int i = 1; i < s.size(); i++){
            dp[i] = i;
            for(int j = i -1; j >= -1; j--){
                //string sub_s = s.substr(j+1,i - j);
                //if (IsPalindrome(sub_s)){
                if (j + 2 <= i -1){
                    pl[j+1][i] = s.at(j+1) == s.at(i) && pl[j+2][i-1];
                }else{
                    pl[j+1][i] = s.at(j+1) == s.at(i); 
                }
                if (pl[j+1][i]){
                    dp[i] = j >=0 ? min(dp[i],dp[j] + 1) : 0;
                }    
            }
        }
        
        int ans = dp[s.size() -1];
        delete []dp;
//delete pl
return ans; } };
posted @ 2013-06-11 23:29  一只会思考的猪  阅读(324)  评论(0编辑  收藏  举报