leetcode------分割回文串

抖抖認真了發表於2020-12-31

解題思路:

這個簡單的方法就是,用回溯,一個個的遍歷。每一次從下一個遍歷之前,都需要判斷當前子串是不是迴文串,這裡的迴文串檢查可以用動態規劃儲存起來,加快速度:

dp[i][j]是不是迴文串,判斷s[i] == s[j] && ( j - i < 3 || dp[i+1][j-1])

class Solution {
public:

    bool IsHUIWEN(string s)
    {
        int l = 0;
        int r = s.size()-1;
        while(l<r)
        {
            if(s[l++]!=s[r--])
                return false;
        }
        return true;
    }

    void backthrough(string s,int cur,vector<string> sub,
                    vector<vector<string>> &res,
                    vector<vector<int>> &dp)
    {
        if(cur>=s.size())
        {
            res.push_back(sub);
            return ;
        }
        for(int i = cur;i<s.size();i++)
        {
            //if(IsHUIWEN(s.substr(cur,i-cur+1)))
            if(s[cur]==s[i] && (i-cur < 3 || dp[cur+1][i-1]))
            {
                dp[cur][i]=1;
                sub.push_back(s.substr(cur,i-cur+1));
                backthrough(s,i+1,sub,res,dp);
                sub.pop_back();
            }
        }
    }


    vector<vector<string>> partition(string s) {
        vector<vector<string>> res ;
        vector<vector<int>> dp(s.size(),vector<int>(s.size()));
        for(int i = 0;i<s.size();i++)
        {
            dp[i][i]=1;
        }
        vector<string> temp;
        backthrough(s,0,temp,res,dp);
        
        return res;
    }

};

下面統計最小的分割回文串

如果沿著上一題的做法,就是將每一次分隔到最後將分割的次數記錄下來,比較大小;但這樣做還是重複記錄了很多次,會超時,從而就再需要輔助空間來降低複雜度;

我們可以從前往後遍歷,即自底向上,用dp[i] 記錄前i個字元是迴文串並且分割次數是最小的,如果j是從中的一次分割,那麼dp[j]表示前j個字元分割回文最小的次數,從0開始遍歷,如果i到j是迴文的,

那麼dp[j]=min(dp[j],dp[i]+1);意思就是說只要從i分割一刀,那麼只要前i個字串迴文分割次數最小dp[i]再加上1,就表示從i分割,此時dp[j]最小。

class Solution {
public:

    bool IsHUIWEN(string s)
    {
        int l = 0;
        int r = s.size()-1;
        while(l<r)
        {
            if(s[l++]!=s[r--])
                return false;
        }
        return true;
    }

    void backthrough(string s,int cur,int num,int &res,vector<vector<int>> &dp)
    {
        if(cur>=s.size())
        {
            res=min(res,num);
            return ;
        }
        for(int i = cur;i<s.size();i++)
        {
            //if(IsHUIWEN(s.substr(cur,i-cur+1)))
            if(s[cur]==s[i] && (i-cur < 3 || dp[cur+1][i-1]))
            {
                dp[cur][i]=1;
                backthrough(s,i+1,num+1,res,dp);
            }
        }
    }

    void cut(string s ,vector<vector<int>> &dp,vector<int> &f)
    {
        int n = s.size();
        for(int i = 1; i <= n; i++){
            //表示剛開始每一處都分割一次
            f[i] = i;
            for(int j = 0; j < i; j++){
                if(s[j]==s[i-1] && (i-1-j < 3 || dp[j+1][i-2])){
                    dp[j][i-1]=1;
                    f[i] = min(f[j] + 1, f[i]);
                }
            }
        }
    }

    int minCut(string s) {
        int res = 999;
        vector<vector<int>> dp(s.size(),vector<int>(s.size()));
        for(int i = 0;i<s.size();i++)
        {
            dp[i][i]=1;
        }
        vector<int> f(s.size()+1);
        f[0]=-1;
        //f[0]是-1很重要,表示從0開始到j就是迴文的,那麼f[0]+1 = 0表示不需要進行分割。
        cut(s,dp,f);
        
        return f[s.size()];;
    }
};

 

相關文章