原文:40. 组合总和 II(力扣 面试题) - 每天一个JavaScript小知识@Js中文网 · 码农进阶题库

原文地址:https://www.javascriptc.com/interview-tips/zh_cn/leetcode/leetcode-javascript-solution-040/

题目:

难度:Middle

相关话题:数组回溯算法

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

candidates 中的每个数字在每个组合中只能使用一次。

说明:

  • 所有数字(包括目标数)都是正整数。

  • 解集不能包含重复的组合。

示例1:

输入: candidates =[10,1,2,7,6,1,5], target =8,
所求解集为:
[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

示例2:

输入: candidates =[2,5,2,1,2], target =5,
所求解集为:
[
 [1,2,2],
 [5]
]

思路:

NO.39区别:

  1. 存在重复数字,需要去重。

  2. 每个数字只能用1次。

对于第一个区别,需要对数组排序,排序是为了能更方便的去重,每次遍历时,检查i>start && candidates[i]===candidates[i-1],其中start是当前回溯的开始索引, 如果条件成立,说明当前值和上一个值是相同的,因此跳过以避免重复。

对于第二个区别,下一次的回溯,都是从索引i+1开始。

/**
 * @来源: Javascript中文网 - 前端进阶资源教程 https://www.javascriptc.com/
 * @介绍:一个致力于帮助开发者用代码改变世界为使命的平台,每天都可以在这里找到技术世界的头条内容
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */
var combinationSum2 = function(candidates, target) {
  let result=[]
  candidates.sort()
  backtrack([],0,target)
  return result

  function backtrack(temp,start,rest){
    if(rest<0)return
    if(rest===0)result.push(temp.slice())
    for(let i=start;i<candidates.length;i++){
      if(i>start && candidates[i]===candidates[i-1])continue
      temp.push(candidates[i])
      backtrack(temp,i+1,rest-candidates[i])
      temp.pop()
    }
  }
};