LeetCode热题(JS版) - 39. 组合总和

291 阅读2分钟

题目描述

给定一个无重复元素的数组 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]
]

解法思路

本题使用回溯算法来解决,先将数组进行排序,然后按照一定的规则依次遍历每个数。

具体做法如下:

  • 定义一个结果数组 res、路径数组 path 和当前位置 start
  • 如果当前路径 path 中的数字和等于目标值 target,那么将当前路径 path 加入到结果数组 res 中。
  • 如果当前路径 path 中的数字和已经大于目标值 target,那么直接返回。
  • 从当前位置 start 开始向后遍历数组 candidates,对于每个数,将其加入到路径 path 中。
  • 然后递归调用函数本身,但是此时的目标和应该减去当前遍历到的数 candidates[i]
  • 递归结束后,将路径 path 中的最后一个数弹出,回溯到上一层继续寻找其他可能性。

代码实现

function combinationSum(candidates: number[], target: number): number[][] {
  const res: number[][] = [];
  const path: number[] = [];

  candidates.sort((a, b) => a - b);

  const dfs = (start: number, target: number) => {
    if (target === 0) {
      res.push([...path]);
      return;
    }
    for (let i = start; i < candidates.length && target >= candidates[i]; i++) {
      path.push(candidates[i]);
      dfs(i, target - candidates[i]);
      path.pop();
    }
  };

  dfs(0, target);

  return res;
}

image.png

复杂度分析

时间复杂度为 O(n^(target/min(candidates))),其中 n 为候选数组 candidates 的长度。因为每个数字可以无限制重复被选取,所以搜索树的深度可以达到 target/min(candidates) 层。

空间复杂度为 O(target/min(candidates)),因为需要存储的路径的长度不会超过 target/min(candidates)