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

目录

  • Leetcode39. 组合总和
  • Leetcode40.组合总和II
  • Leetcode131.分割回文串

Leetcode39. 组合总和

文章链接:代码随想录
题目链接:39. 组合总和

思路:和组合问题的不同在于这里的元素不重复但可以重复选取,startIndex设为i。
未剪枝:

class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;
    void backtracking(vector<int>& candidates, int target, int sum, int startIndex){
        if (sum == target){
            res.push_back(path);
            return ;
        }
        else if (sum > target) {
            return ;
        }
        for (int i = startIndex; i < candidates.size(); i++){
            path.push_back(candidates[i]);
            backtracking(candidates, target, sum + candidates[i], i);
            path.pop_back();
        }

    }
    
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        backtracking(candidates, target, 0, 0);
        return res;
    }
};

排序后剪枝:

class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;
    void backtracking(vector<int>& candidates, int target, int sum, int startIndex){
        if (sum == target){
            res.push_back(path);
            return ;
        }
        for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++){
            path.push_back(candidates[i]);
            backtracking(candidates, target, sum + candidates[i], i);
            path.pop_back();
        }

    }
    
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        sort(candidates.begin(), candidates.end());
        backtracking(candidates, target, 0, 0);
        return res;
    }
};

Leetcode40.组合总和II

文章链接:代码随想录
题目链接:40.组合总和II

思路:与上一题不同在于元素右重复但不可以重复选取,若用上一题的方法可能会导致有重复答案出现。去重的逻辑在于纵向(树枝)不去重,横向(数层)去重;也就是递归不去重,在for循环中去重。注意需要先对数组排序。
利用used数组去重:

 class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;
    void backtracking(vector<int>& candidates, int target, int sum, int startIndex,vector<bool>& used){
        if (sum == target){
            res.push_back(path);
            return ;
        }
        for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++){
            if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false) continue;
            path.push_back(candidates[i]);
            used[i] = true;
            backtracking(candidates, target, sum + candidates[i], i + 1, used);
            used[i] = false;
            path.pop_back();
        }
    }
    
    
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
       vector<bool> used(candidates.size(), false);
       sort(candidates.begin(), candidates.end());
       backtracking(candidates, target, 0, 0, used);
       return res;
    }
};

利用startIndex去重(感觉这种方法更容易理解些,写起来也简便些):

 class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;
    void backtracking(vector<int>& candidates, int target, int sum, int startIndex){
        if (sum == target){
            res.push_back(path);
            return ;
        }
        for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++){
            if (i > startIndex && candidates[i] == candidates[i - 1]) continue;
            path.push_back(candidates[i]);
            backtracking(candidates, target, sum + candidates[i], i + 1);
            path.pop_back();
        }
    }
    
    
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
       sort(candidates.begin(), candidates.end());
       backtracking(candidates, target, 0, 0);
       return res;
    }
};

Leetcode131.分割回文串

文章链接:代码随想录
题目链接:131.分割回文串

思路:重点在于理解题意,判断一段是回文串就找下一个切割线,不是就把这个切割线开始的切割范围向后挪,如果切割线(也就是startIndex)能够走到字符串最后,说明找到了一组结果;如果切割范围挪到最后也不是回文串,res将不会收录这组path里的数据,path的数据会pop_back()出去并把切割线(startIndex)位置向后挪。(这里有点绕,思考了好一会,感觉干想会很头痛,边把思路写出来边想会理解的快一些)

class Solution {
public:
    vector<vector<string>> res;
    vector<string> path;
    void backtracking(const string& s, int startIndex){
        if (startIndex >= s.size()){
            res.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;
    }
    
    vector<vector<string>> partition(string s) {
        backtracking(s, 0);
        return res;
    }
};

另外这里判断回文串的方法没看动态规划的那种,等刷到动态规划再回来写一下。
第二十六天休息,第二十七天打卡,昨晚半夜醒了没睡着,今天上午一直在睡,也没健身,希望今天睡眠好一些。
加油!!!

你可能感兴趣的:(算法)