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.

思路一

用递归得到所有可能的划分,可以参考上篇博文Palindrome Partitioning,然后求取最短的划分。

但是我们没必要存取所有的划分结果,只需要存储划分段数就可以了。

对空间的改进

class Solution {
public:
    int minCut(string s) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int len = s.length();   
        if(len<1) return 0;
        vector<string> vec;
        int min = INT_MAX; 
        mypart(vec, 0, s, min);     
        return min-1;
    }
     void mypart(vector<string> &vec, int cur, string &S, int &min) {
         if(cur==S.length()) {
             if(vec.size()<min)
                 min = vec.size();
             return ;
         }
         for(int i=cur;i<S.length();i++) {
             int len = i-cur+1;
             string str = S.substr(cur,len);
             if(ispalind(str)) {
                 vec.push_back(str);
                 mypart(vec, i+1, S, min);
                 vec.pop_back();
             }
         }         
     }  
     
     bool ispalind(string &S) {
         if(S.empty())  
             return true;
         int i=0, j=S.length()-1;
         while(i<j) {
             if(S[i]!=S[j])
                 return false;
             i++;
             j--;
         }    
         return true;
     }  
     
};

对大数据虽然没有内存限制了,但是还是出现了  Run Status:  Time Limit Exceeded

因为我们还可以进一步的 剪枝优化 步的:如果当前子字符串生成的回文划分段数已经超过了 min ,就没必要接着进行下去了。

剪枝优化时间

         for(int i=cur;i<S.length();i++) {
             int len = i-cur+1;
             string str = S.substr(cur,len);
             if(vec.size()<=min && ispalind(str)) {
                 vec.push_back(str);
                 mypart(vec, i+1, S, min);
                 vec.pop_back();
             }
         } 

或者

         if(vec.size()+1>min)
             return ;
         for(int i=cur;i<S.length();i++) {
             int len = i-cur+1;
             string str = S.substr(cur,len);
             if(ispalind(str)) {
                 vec.push_back(str);
                 mypart(vec, i+1, S, min);
                 vec.pop_back();
             }
         } 

但好像都还是未能通过大数据。

原因是 虽然加入剪枝,但是算法的基本思想还是遍历,数量级未改变,依旧是 O(N*N) 。

下面考虑要降低数量级了。

思路二

用DP动态规划的思想:

二维标志数组 ispalin[i][j] 记录 s 的 i~j 子串是否是回文的;

一维数组 num[i] 记录 s 的 i~len-1 分割后的最小段数,初始化时 num[0]=len, ... , num[len-1]=1;

最优结果是 num[0]-1 。

动态规划过程:

(1)如果s[i]=s[j] 并且 ispalin[i+1][j-1]=true ,则表示 i~j 也是回文,即  ispalin[i][j]=true。

(2)如果s[i]=s[j] 并且 ispalin[i][j]=true,则 num[i] = min(num[i], num[j+1]+1) ,即更新当前 i~len-1子串的最小段数。

class Solution {
public:
    int minCut(string s) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int len = s.length();
        if(len<2)  return 0;
        vector<vector<bool>> ispalin(len,vector<bool>(len,false));
        vector<int> num(len+1,0);
        for(int i=0;i<len;i++)
            num[i] = len-i;
        for(int i=len-1;i>=0;i--) {
            for(int j=i;j<len;j++) {
                if(s[i]==s[j]) {
                    if(j-i<2) {
                        ispalin[i][j]=true;
                        num[i] = min(num[i],num[j+1]+1);
                    }else if(ispalin[i+1][j-1]) {
                        ispalin[i][j]=true;
                        num[i] = min(num[i],num[j+1]+1);
                    }                    
                }
            }  
        }   
        return num[0]-1;        
    }
};

其实时间复杂度也是 O(N*N)的,但是对大数据轻松通过了。

与思路一比较:

优点在,对当前的子串是否是回文的判断上要更优,避免重复判断。

例如:如果 s1=abba 是回文,当增加长度时 s2=dabbad ,

思路一:再遍历一遍 s2 ,时间 O(length(s2))

思路二:比较新增加的字符是否相等,同时判断s1是否是回文,时间O(2+1)

所以高下优劣立见。

如果仔细分析计算:

(1)思路一的时间复杂度是 O(N*N*length(str))

(2)DP的时间复杂度是 O(N*N*2)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值