代码随想录算法训练营29期Day27|LeetCode 39,40,131

发布时间:2024年01月22日

文档讲解:组合总和??组合总和II??分割回文串

39.组合总和

题目链接:https://leetcode.cn/problems/combination-sum/description/

思路:

? ? ? ?很简单,因为每个数选取的次数为无限个,因此我们在搜索时有两种选取情况:下一步依旧选取当前这个数或者下一步选取下一个位置的数,递归边界条件为位置走到头的时候或者和超过目标值的时候。当和恰好为目标值,证明找到了一种方案。

核心代码:

class Solution {
private:
    vector<vector<int>> ans;
    vector<int> nums;
    vector<int> cand;
    int tmp,n;
    void dfs(int x,int num){
        if(num>tmp) return;
        if(num==tmp){
            ans.push_back(nums);
            return;
        }
        if(x==n) return;
        nums.push_back(cand[x]);
        dfs(x,num+cand[x]);
        nums.pop_back();
        dfs(x+1,num);
    }
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        cand=candidates;
        tmp=target;
        n=candidates.size();
        dfs(0,0);
        return ans;
    }
};

40.组合总和II

题目链接:https://leetcode.cn/problems/combination-sum-ii/description/

思路:

? ? ? ? 本题与上一道题目类似。我们可以预处理下给出的数组,统计每个值出现的次数,将每个值视为只在数组中出现一次,且可多次选取,最多选取次数也已给出。这样的话,我们在递归时在每层将一个值的出现次数用for循环全部枚举完就可以了。

????????递归边界条件依旧是位置走到头或者和超过目标值的时候。当和恰好为目标值,证明找到了一种方案。

核心代码:

class Solution {
private:
    vector<pair<int, int>> tot;
    vector<vector<int>> ans;
    vector<int> path;

public:
    void dfs(int pos, int rest) {
        if (rest == 0) {
            ans.push_back(path);
            return;
        }
        if (pos == tot.size() || rest < tot[pos].first) {
            return;
        }

        dfs(pos + 1, rest);

        int maxn = min(rest / tot[pos].first, tot[pos].second);
        for (int i = 1; i <= maxn; ++i) {
            path.push_back(tot[pos].first);
            dfs(pos + 1, rest - i * tot[pos].first);
        }
        for (int i = 1; i <= maxn; ++i) {
            path.pop_back();
        }
    }

    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(), candidates.end());
        for (int num: candidates) {
            if (tot.empty() || num != tot.back().first) {
                tot.emplace_back(num, 1);
            } else {
                ++tot.back().second;
            }
        }
        dfs(0, target);
        return ans;
    }
};

131.分割回文串

题目链接:https://leetcode.cn/problems/palindrome-partitioning/description/

思路:

? ? ? ? 本题目我们可以像分割区间那样枚举,是否能分割则需要判断分割掉的区间是否是回文串。比方说我们现在[1,a]的区间已经分割好了,分割成了多少段我不需要管,下面需要分割[a+1,n],我就分别从?a+1,a+2,a+3......等处分割,是否可以分割取决于 [a+1,a+1],[a+1,a+2],[a+1,a+3]......是否是回文串。

? ? ? ? 递归边界条件为分割线位置走到最后,同时分割线走到最后也证明前面全部分割成功为回文子串。

核心代码:

class Solution {
private:
    vector<vector<string>> result;
    vector<string> path;
    void backtracking (const string& s, int startIndex) {
        if (startIndex >= s.size()) {
            result.push_back(path);
            return;
        }
        for (int i = startIndex; i < s.size(); i++) {
            if (isPalindrome(s, startIndex, i)) {
                string str = s.substr(startIndex, i - startIndex + 1);
                path.push_back(str);
            } else {
                continue;
            }
            backtracking(s, i + 1);
            path.pop_back();
        }
    }
    bool isPalindrome(const string& s, int start, int end) {
        for (int i = start, j = end; i < j; i++, j--) {
            if (s[i] != s[j]) {
                return false;
            }
        }
        return true;
    }
public:
    vector<vector<string>> partition(string s) {
        result.clear();
        path.clear();
        backtracking(s, 0);
        return result;
    }
};

今日总结

????????今日学习时长3h,题目不算简单。昨天高烧,今天还在打针,勉强做了一下写了一下。

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