【算法复习·每日一题】组合总和·回溯剪枝

组合总和·回溯剪枝

  • 题目
  • 思路
    • 题目解答
  • 变形
    • 题目
    • 思路
    • 题目解答
  • Try It Out

题目

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target的组合。candidates 中的数字可以无限制重复被选取。

说明:

所有数字(包括 target)都是正整数。 解集不能包含重复的组合。

思路

和【算法复习·每日一题】组合问题·回溯法 中的思路差不多。

此刻,想象一下组合里选数的树状结构,这个树每下一层target就要减掉一个数。最后会减到0或者负数。

递归停止的条件不是到叶子节点停止,而是到减到0或者负数停止。(此为剪枝)

两种情况:

  1. 减到0:保存的路径为一个答案。
  2. 减到负数:不是答案,直接返回。

题目解答

按照昨天的回溯问题的模板来解决这个问题很简单~

class Solution {
public:
    vector<int> path; // 保存可能的结果
    vector<vector<int>> res; //保存结果集合
    void backtracking(vector<int>& candidates, int target) {
        if (target == 0) { 
        	// 减到0
            res.push_back(path);
            return;
        }
        else if (target < 0) {
        	// 减到负数
            return;
        }

        for(auto& e : candidates) {
        	// 防止出现重复答案,设定我们的答案为前一个数<=后一个数
            if(path.size() != 0 && e > path.back()) continue; 
            path.push_back(e); // 处理当前节点
            backtracking(candidates, target - e);
            path.pop_back(); // 回溯
        }

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

变形

题目

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用一次。

说明:

所有数字(包括目标数)都是正整数。 解集不能包含重复的组合。

思路

和上一题的区别就是candidates 中的每个数字在每个组合中只能使用一次。

所以需要一个去重的操作,我这里用的非常简单粗暴。。。即排序+判断

每一轮选择中,都只能选当前数index之后的数,并且还不能选重复的数。那么只需要在index之后的数重复时跳过它就好啦~

if(i!=0 && candidates[i]==candidates[i-1] && i-1 >= idx) 	
	continue;

其他和上一题想法那简直就是一模一样。

题目解答

#include // sort函数所在的头文件

class Solution {
public:
    vector<int> path; // 保存可能的结果
    vector<vector<int>> res; //保存结果集合
    void backtracking(vector<int>& candidates, int target, int idx) {
        if (target == 0) { 
        	// 减到0
            res.push_back(path);
            return;
        }
        else if (target < 0) {
        	// 减到负数
            return;
        }

        for(int i = idx; i < candidates.size(); i++) {
        	// 防止出现重复答案: 和上一个数字相同,并且上一个数字也在这轮选择中的 跳过
            int e = candidates[i];
            if(i!=0 && candidates[i]==candidates[i-1] && i-1 >= idx) continue;

            path.push_back(e); // 处理当前节点
            backtracking(candidates, target - e, i+1);
            path.pop_back(); // 回溯
           
        }

    }
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(), candidates.end()); // 排个序
        backtracking(candidates, target, 0); 
        return res;
    }
};

Try It Out

39.组合总和-力扣(LeetCode)
40.组合总合2-力扣(leetCode)

你可能感兴趣的:(算法复习,算法,leetcode)