我们将回溯想象成在深度遍历一颗数,每一种路径都是一个选择,在 backtrack 函数开头判断结果是否添加此选项。
在回溯中,我们想象一个数组 [] 为路径,那么每次选择都是往路径中添加节点,因此,就要考虑每次节点的选项。
在下题中,for(let i = idx; i < nums.length; i++)
,这里idx
可以视为路径中此刻的位置,类似于二叉树的当前层数。
因为不可以包含重复的子集,所以之前走过的节点不可以再取了,因此我们在进入回溯的时候idx
需要+1
剑指 Offer II 079. 所有子集
给定一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
var subsets = function(nums) {
const res = []
const backtrack = (idx, path) => {
res.push([...path])
for(let i = idx; i < nums.length; i++){
path.push(nums[i]); // 添加
backtrack(i + 1, path)
path.pop(); //回溯
}
}
backtrack(0, [])
return res;
};
回溯算法在选择当前节点的时候,遍历当前所有的可选项。
本题可作为回溯题目的模板,主要变化在于递归终止条件、每轮可遍历的选项和选择结果路径。
剑指 Offer II 081. 允许重复选择元素的组合
给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。
candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的唯一组合数少于 150 个。
var combinationSum = function(candidates, target) {
const res = []
const backtrack = (idx, sum, path) => {
if(sum === target){
// 添加结果路径
res.push([...path])
}else if(sum > target) return //如果sum超过target就直接return
for(let i = idx; i < candidates.length; i++){
path.push(candidates[i])
backtrack(i, sum + candidates[i], path) //下次还可以选此元素
path.pop()
}
}
backtrack(0, 0, [])
return res;
};
解答:本题需要注意的是元素可以多次选择,那么在进入下次选择的时候,依旧可以选择当前元素,idx
不需要+1
。
剑指 Offer II 082. 含有重复元素集合的组合
给定一个可能有重复数字的整数数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次,解集不能包含重复的组合。
var combinationSum2 = function(candidates, target) {
const res = []
candidates.sort()
const backtrack = (idx, sum, path) => {
// 终止条件
if