40 组合总数II

2022-5-12 LeetCode回溯

标签:回溯 中等

# 题目

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

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

注意:解集不能包含重复的组合。

示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
1
2
3
4
5
6
7
8

示例 2:

输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]
1
2
3
4
5
6

提示:

  • 1 <= candidates.length <= 100
  • 1 <= candidates[i] <= 50
  • 1 <= target <= 30

# 题解

题目特点:

  1. 取同一集合中的数组成一个组合
  2. 所给的数组中有重复的数,但是组合不能重复

这一题与组合问题最大的区别就是数组中有重复出现的数,但是要求组合不能重复,有两种办法:

  1. 按之前的思路求出所有组合,然后对组合进行去重
  2. 在找组合的过程中就实现去重的效果

第一种过于麻烦,因为每一个组合都是使用数组存储的,且组合一样,但是组合中的数在数组中的顺序不一样,很麻烦;

第二种就是先对给定的数组集合进行排序,让相同数字放在一起,然后控制循环过程中,如果出现同一数字,就跳过,以免重复

/**
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */
var combinationSum2 = function(candidates, target) {
  const res = [], temp = [];
  let sum = 0;
  candidates.sort((a, b) => a - b); // 给candidates排序,让相同的数字在一块,后面好判断同一层是否组合重复了
  function backtracing(startIndex) {
    if(sum === target) {
      res.push(Array.from(temp));
      return ;
    }
    for(let i=startIndex; i<candidates.length && sum+candidates[i]<=target; i++) {
      // 要对同一树层使用过的元素进行跳过
      if(i>startIndex && candidates[i]===candidates[i-1]) continue;
      sum += candidates[i];
      temp.push(candidates[i]);
      backtracing(i+1);
      temp.pop();
      sum -= candidates[i];
    }
  }
  backtracing(0);
  return res;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27