LeetCode39. 组合总和

198 阅读1分钟

「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战

组合总和

题目

给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出candidates 中所有可以使数字和为目标数 target 的唯一组合。candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是唯一的。 

对于给定的输入,保证和为 target 的唯一组合数少于 150 个。

示例 1:

输入: candidates = [2,3,6,7], target = 7
输出: [[7],[2,2,3]]

示例 2:

输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]

示例 3:

输入: candidates = [2], target = 1
输出: []

示例 4:

输入: candidates = [1], target = 1
输出: [[1]]

示例 5:

输入: candidates = [1], target = 2
输出: [[1,1]]

提示:

  • 1 <= candidates.length <= 30
  • 1 <= candidates[i] <= 200
  • candidate 中的每个元素都是独一无二的。
  • 1 <= target <= 500

解题思路

对于candidates = [2,3,6,7], target = 7,我们来分析他构建组合的思路,首先取一个数时,他有4种选择,选2,选3,选6,选7,对于每种选择的下一层递归而言,是需要在各自区间下取值,才能不尽相同,比如选2的,下一层要在[2,3,6,7]中选择;选3的,下一层要在[3,6,7]中选择,选6的,下一层要在[6,7]中选择,选7的只能在[7]这一区间相同,这样的递归过程构建成了一颗树的结构,当选取的数,相加和大于sum时,直接进入下一种选择,<sum的继续递归,在对应区间取值,等于sum的结束当前分支递归,将组合压入结果栈中。

  • 递归的终止条件:当传入的sum大于target时,递归结束(剪枝),当传入的sum等于于target时,将组合压入结果栈中,递归结束
  • 递归的传入参数和返回值:无返回值,传入当前sum,和当前已组合的数值集合
  • 递归的单层逻辑:当选取的数,相加和大于sum时,直接进入下一种选择,<sum的继续递归,在对应区间取值,等于sum的结束当前分支递归,将组合压入结果栈中
var combinationSum = function(candidates, target) {
    const selectNum = function(index,sum){
        if (sum > target) return;
        if (sum === target){
            res.push(Array.from(path));
            return;
        }
        // 初始有candidates.length取值区间,candidates.length种选择
        for(let i = index; i < candidates.length; i++) {
            let n = candidates[i];
            // 该取值空间不满足要求,直接进行该层递归的下一选择
            if(n > target - sum) continue;
            path.push(n);
            sum += n;
            selectNum(i, sum);
            path.pop();
            sum -= n;
        } 
    }

    let res = [];
    let path = [];
    // 对数组排序,方便取值求和比较
    candidates.sort()
    selectNum(0,0);
    return res;
};