40. 组合总和 II回溯Normal
Posted pre_eminent
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了40. 组合总和 II回溯Normal相关的知识,希望对你有一定的参考价值。
难度中等
给你一个由候选元素组成的集合 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 <= candidates.length <= 100
1 <= candidates[i] <= 50
1 <= target <= 30
思路
1. 与39.组合总和不同的是,每一个元素只能用一次
2. 与39.组合总和相同的是,结果集中不能有重复的
3. 在回溯前,必须先排序
4. 在回溯中,每一个元素只能选 或者 不选
5. 如果是不选,那么它身后和它相邻的同样的数字要全部跳过(防止重复结果)
6. 并且选的情形要放在前面,不选的情形放后面
解答:
/**
* @param number[] choiceArr
* @param number target
* @return number[][]
*/
var combinationSum2 = function(choiceArr, target)
// 必须先排序(会有相同的数字)
choiceArr.sort((a,b)=>return a-b;);
let res = [];
let path = [];
// 重点:相同的数字不能重复选取
backtrack(0, target, choiceArr, path, res);
return res;
;
function backtrack(currentIndex, target, choiceArr, path, res)
// 结束条件有两种情况
// 1. target == 0了,即找到组合方法了
if (target === 0)
// 注意js 数组共用内存
let pathCopy = [...path];
res.push(pathCopy);
return;
// 2. currentIndex 已经到choiceArr末尾了
if (currentIndex === choiceArr.length)
return;
// 对于当前选项,
// 有两种情况:采用 或者 不采用
let currentChoice = choiceArr[currentIndex];
// 1. 必须先采用当前的数字,
// 前提是:剩余空间还足够时
let newTarget = target - currentChoice;
if (newTarget >= 0)
// 做出选择
path.push(currentChoice);
// 进入下一层
backtrack(currentIndex + 1, newTarget, choiceArr, path, res);
// 撤销刚才的选择
path.pop();
// 2.然后才是 不使用当前的数字,
// 直接进入下一层
// 进入下一层之前,必须要跳过所有与它相同的数字(因为已经决定 不采用该数字了)
while(currentIndex < choiceArr.length && choiceArr[currentIndex] === currentChoice)
currentIndex++;
backtrack(currentIndex, target, choiceArr, path, res);
以上是关于40. 组合总和 II回溯Normal的主要内容,如果未能解决你的问题,请参考以下文章
代码随想录|day26|回溯算法part03● 39. 组合总和● 40.组合总和II● 131.分割回文串
递归与回溯7:LeetCode40. 组合总和 II(不可重复)