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

本文介绍了一种使用回溯和动态规划解决LeetCode中的分割回文串问题。通过动态规划提前判断子串是否为回文,然后自底向上遍历,用dp数组记录分割次数达到最小值,以此降低复杂度并避免超时。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

解题思路:

这个简单的方法就是,用回溯,一个个的遍历。每一次从下一个遍历之前,都需要判断当前子串是不是回文串,这里的回文串检查可以用动态规划储存起来,加快速度:

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()];;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值