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

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

39.组合总和

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

思路:

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

核心代码:

class Solution {
private:
    vector> ans;
    vector nums;
    vector 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> combinationSum(vector& 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> tot;
    vector> ans;
    vector 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> combinationSum2(vector& 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> result;
    vector 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> partition(string s) {
        result.clear();
        path.clear();
        backtracking(s, 0);
        return result;
    }
};

今日总结

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

你可能感兴趣的:(代码随想录算法训练营29期,算法,leetcode,职场和发展,c++)