leetcode132

刷题主页

给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回符合要求的最少分割次数。
示例:
输入: “aab”
输出: 1
解释: 进行一次分割就可将 s 分割成 [“aa”,“b”] 这样两个回文子串。

最少分割次数,因此使用动态规划。读题可以发现,其实这道题属于字符串字典一类的问题,只是这里没有给出字典,而是使用某子串是否为回文串,但是整体思路是一样的,设dp[i]表示前i个字符的最少分割次数,如果s[j:i]是回文串,那么dp[i]=min(dp[i],dp[j-1]+1),然后直接遍历即可。

int minCut(string s) {
        int len=s.size();
        if(len<=1)return 0;
        vector<int>dp(len,0);
        //初始化
        for(int i=0;i<len;++i){
            dp[i]=i;
        }
        for(int i=1;i<len;++i){
            if(check(s.substr(0,i+1))){
                dp[i]=0;
                continue;
            }
            for(int j=i;j>=1;--j){
                string temp=s.substr(j,i-j+1);
                if(check(temp)){
                    dp[i]=min(dp[i],dp[j-1]+1);
                }
            }
        }
        return dp[len-1];
    }
    //判断子串是否为回文串
    bool check(string s){
        int left=0,right=s.size()-1;
        while(left<right){
            if(s[left]!=s[right])return false;
            ++left;
            --right;
        }
        return true;
    }

但是这样会在某些样例中超时,因为在进行回文串判断时,进行了大量的重复运算,最终的时间复杂度是O(N^3),我么可以进行优化,即不需要在进行遍历判断是否为回文串,我们可以直接将某子串是否为回文串提前记录下来,这样就把时间复杂度缩减到平方级别,代码如下:

int minCut(string s){
        int len=s.size();
        if(len<=1)return 0;
        vector<int>dp(len,0);
        vector<vector<bool>>check(len,vector<bool>(len,false));
        setmap(check,s);
        for(int i=0;i<len;++i){
            dp[i]=i;
        }
        for(int i=1;i<len;++i){
            if(check[0][i]){
                dp[i]=0;
                continue;
            }
            for(int j=i;j>=1;--j){
                if(check[j][i]){
                    dp[i]=min(dp[i],dp[j-1]+1);
                }
            }
        }
        return dp[len-1];
    }
    //二维数组记录check[i][j]表示s[i:j]是否为回文串
    void setmap(vector<vector<bool>>&check,string s){
        int len=s.size();
        //先记录长度为1和2的是否为回文串
        for(int i=0;i<len;++i){
            check[i][i]=true;
            if(i>0){
                if(s[i]==s[i-1]){
                    check[i-1][i]=true;
                }
            }
        }
        //记录长度大于等于3的是否为回文串
        for(int i=2;i<len;++i){
            for(int j=0;j+i<len;++j){
                if(s[j]==s[j+i]){
                    check[j][j+i]=check[j+1][i+j-1];
                }
            }
        }
    }

你可能感兴趣的:(Leetode刷题系列)