每天一道leetcode(Day 46)


39. 组合总和

题目描述

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

candidates  中的数字可以无限制重复被选取。

说明:

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

示例

  • 示例  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]
]

解题思路

  • 思路
    由题可知,原数组元素不重复,题目需要寻找一个符合条件的组合,且原数组的单个元素可以重复使用,只要结果中的子组合互不相同即可;

  • 求解

    • 原数组的单个元素可以重复使用

      • 意味着下一个 for 循环中的元素选取,要从前一个元素开始,因为可以重复使用,不然如果跟着 for 的自增变量 i 走,会漏掉可能解

      • 将自增变量 i 传递下去

    • 终止条件
      target 一一减去符合组合的元素,最终为 0 ,才是一个符合题意的组合

代码模板:

解决一个回溯问题,实际上就是一个决策树的遍历过程。我们只需要考虑三个问题:

  1. 路径:也就是已经做出的选择。

  2. 选择列表:也就是你当前可以做的选择。

  3. 结束条件:也就是到达决策树底层,无法再做选择的条件。

其对应的代码模板就是:

res = []

def back_track(路径,选择列表):
    if 满足结束条件:
        res.add(路径)
        return

for 选择 in 选择列表:
    做选择
    back_track(路径,选择列表)
    撤销选择

其核心就是 for 循环里面的递归,在递归调用之前「做选择」,在递归调用之后「撤销选择」(还原选择状态进行下一次选择)

代码

/**
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */
var combinationSum = function (candidates, target) {
  let n = candidates.length,
    res = [],
    tempRes = [];
  let backTrack = (tempRes, target, start) => {
    if (target < 0) {
      return;
    }
    if (target === 0) {
      res.push(tempRes);
      return;
    }
    for (let i = start; i < n; i++) {
      tempRes.push(candidates[i]);
      backTrack(tempRes.slice(), target - candidates[i], i);
      tempRes.pop();
    }
  };
  backTrack(tempRes, target, 0);
  return res;
};

参考


文章作者: CassielLee
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 CassielLee !
评论
  目录