LeetCode 40:组合总和Ⅱ(Javascript 解答)

原题目

给定一个候选人编号的集合 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]
]

示例 2:

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

解题思路

图解
在这里插入图片描述

  1. 个人觉得解一个题目先画出它的数据结构,这样能理清数据处理的逻辑关系,如上图解,数据是一层层遍历的,可以联想到递归。
  2. 题目说到数组中的每个数字在每个组合中只能使用一次,也就是说在下一层遍历的时候就要跳过当前的元素。

例如:
第一层 [1]
第二层 就只能从剩下的 [2, 2, 2, 5] 中遍历,跳过 1 ,这里假设遍历了第一个 2,那么此时解集是 [1, 2]
第三层 就只能从 [2, 2, 5] 中遍历,要跳过 第一个2 ,以此类推

  1. 题目说明了解集不能包含重复的组合。再看一下图解,你会发现如果每层遍历的元素相同,那么就会得到重复解。所以每层要排除相同的元素(去重)。为了方便去重,先对数组进行排序,然后每层中相邻元素相同,就剪掉该分支。

例如:
第一层 [1]
第二层中可以让1 和 剩下的 [2, 2, 2, 5] 这四个数中的任意一个相加,也就是这一层可以得到 [1, 2], [1, 2], [1, 2], [1, 5]。你是不是发现在这层,解集开始重复了? 导致这个结果的原因就是因为这层遍历的元素有三个 2 ,所以会得到三个相同的解集。

代码

var combinationSum2 = function (candidates, target) {
  // 初始化一个数组,因为结果是数组
  let res = [];

  // 对数组进行排序,方便去重
  candidates.sort((a, b) => a - b);

  let ope = (cur, start, sum) => {
    // 防止爆栈
    if (sum >= target) {
      if (sum === target) {
        // 存储本轮遍历的结果
        res.push(cur);
      }
      return;
    }

    // 遍历数组
    for (let i = start; i < candidates.length; i++) {
      // 思路3: 剪掉本层相同的元素
      if (i > start && candidates[i] === candidates[i - 1]) {
        continue;
      }

      cur.push(candidates[i]);

      // 思路2: 跳过下一层中与当前相同的元素
      ope(cur.slice(), i + 1, sum + candidates[i]);

      cur.pop();
    }
  };

  ope([], 0, 0);
  return res;
};

console.log(combinationSum2([10, 1, 2, 7, 6, 1, 5], 8));

备注

cur.pop();

代码中的这句,一开始我没想通,但是再画画图解就变得很明了了。
pop() 方法,就是删除数组中的最后一项,那么为什么要删除最后一项呢?目的是为了去掉导致解集不正确的最后一层的遍历,然后再去遍历该层其他的元素。

比如:
输入的数组是 [10, 1, 2, 7, 6, 1, 5] , target 是 8
排序后的数组为 [1, 1, 2, 5, 6, 7, 10]
第一层 [1]
第二层 [1, 1]
第三层 [1, 1, 2]
第四层 [1, 1, 2, 5]
第五层 [1, 1, 2, 5, 6] 注意此时 sum(数组元素总和) 已经 大于 target 了。也就是说此时的解集已经是错误的了,那么这一层就是导致解集不正确的最后一层的遍历,那么 cur.pop() 就会删掉这层遍历的结果,也就是使遍历回到第四层 [1, 1, 2, 5],然后再重新选择第五层的遍历元素。
如果第五层的所有可遍历的元素都是错误的,那么就会删掉第四层的遍历结果,也就是使遍历回到第三层 [1, 1, 2],然后再重新选择第四层的遍历元素
以此类推,直到回到第二层 [1, 1]时,重新选择第三层的遍历元素为 6 时,sum === target 得到解集,然后添加到 res 数组中 [[1, 1, 6]]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梁什么鸭,

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值