【代码随想录算法训练营第二十七天|39. 组合总和、40.组合总和II、131.分割回文串】

发布时间:2024年01月22日

代码随想录算法训练营第二十七天|39. 组合总和、40.组合总和II、131.分割回文串

题解参考y总的:http://www.acwing.com

39. 组合总和

我是一看就会,一写就废。先看代码:

class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        dfs(candidates,target,0);
        return res;
    }

    void dfs(vector<int>& candidates,int target,int n)
    {
        if(target == 0)
        {
            res.push_back(path);
            return;
        }
        if(n == candidates.size()) return;
        for(int i = 0;candidates[n] * i <= target;i++)
        {
            dfs(candidates,target - candidates[n]*i,n + 1);
            path.push_back(candidates[n]);
        }
        for(int i = 0;candidates[n] * i <= target;i++)
        {
            path.pop_back();
        }

    }
};

这道题目使用模板,关键在两点,一个是递归结束条件,一个是递归过程。首先是递归的结束条件,递归的结束条件就是和前面组合||一样,当target为0的时候,就结束。然后递归的过程,因为这里每个的元素是无限重复选取的,所以使用 i * candidates[n],这里n代表下标为n的元素。

40.组合总和II

看代码:

class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;

    vector<vector<int>> combinationSum2(vector<int>& c, int target) {
        sort(c.begin(),c.end());
        dfs(c,target,0);
        return res;
    }

    void dfs(vector<int>& c,int target,int n)
    {
        if(!target)
        {
            res.push_back(path);
            return;
        }
        if(n == c.size()) return;
        int k = n + 1;
        while(k < c.size() && c[k] == c[n]) k++;
        int cnt = k - n;
        for(int i = 0;c[n] * i <= target && i <= cnt;i++)
        {
            dfs(c,target - c[n] * i,k);
            path.push_back(c[n]);
        }
        for(int i = 0;c[n] * i <= target && i <= cnt;i++)
        {
            path.pop_back();
        }
    }
}; 

和第一个一样,只不过这里的元素变成有限个数了,所以首先要统计元素个数,这里借鉴的y的,先从小到大排个序,然后统计一个元素重复的个数,还是使用candidates[n] * i,只要i不超过限制的个数就可以。还可以使用hash表来记录元素的个数。

131.分割回文串

看代码:

class Solution {
public:
    vector<vector<bool>> f;
    vector<vector<string>> res;
    vector<string> path;
    vector<vector<string>> partition(string s) {
        int n = s.size();
        f = vector<vector<bool>>(n,vector<bool>(n));
        for(int j = 0;j < n;j++)
        {
            for(int i = 0;i <= j;i++)
            {
                if(i ==j) f[i][j] = true;
                else if(s[i] == s[j])
                {
                    if(i + 1 > j - 1 || f[i + 1][j - 1]) f[i][j] = true;
                }
            }
        }
        dfs(s,0);
        return res;

    }

    void dfs(string s,int n)
    {
        if(n == s.size()) res.push_back(path);
        else
        {
            for(int i = n;i < s.size();i++)
            {
                if(f[n][i])
                {
                    path.push_back(s.substr(n,i - n + 1));
                    dfs(s,i + 1);
                    path.pop_back();
                }
            }
        }
    }
};

首先要判断一个字串是不是回文,首先第一种方法可以使用双指针的方法,一个从头开始,一个从尾开始,只要每次向中间走都字符都相同,那就是回文。
还有一种方法是:(下图来自acwing截图)
在这里插入图片描述首先判断i到j串,第i位和第j位是相同的字符,然后第i+1和第j-1也是回文,这就用的是递归,第一个方法用的是迭代。
f就是用来记录从第i到j位是否是回文串的。首先先构造f,如果是i==j,也就是单个字母,单个字母肯定的是回文;然后判断s[i]和s[j]是否相等,如果相等,再判断一下,如果是i + 1 > j - 1(也就是就只有两个字母),因为之前已经判断了s[i] == s[j]了,所以就两个字母肯定是回文;或者f[i + 1][j - 1]也是回文,那i到j就是回文。
构建好回文记录表f之后,开始走模板第一步,判断条件,什么时候才算一轮的结果,那必须是所有字母都走过一遍的时候,才是加入一个path的时候,然后然后i从n开始,i每次向后走,每次都判断一下n到i是否是回文,如果是的话就加入答案中。
回到一个地方:有人可能注意到,递归的时候dfs后面是i+1,而不是n+1,我个人认为是如果是n+1的话,因该就已有一条路径了,因为每次递归下去,再回溯到开始的时候,就是最开始的n,它就不变了,最后答案中估计也就一条正确答案,比如aab,可能答案只有:[[“a”,“a”,“b”]]其他没有了,因为回溯到开始n不变了。也就是说如果是n+1,外面的for循环相当于没有作用。
在这里插入图片描述

文章来源:https://blog.csdn.net/qq_44810048/article/details/135756906
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。