之前讲解了使用试探-回溯法求解全排列,我们都学过排列组合,其中的组合也是非常适合用试探-回溯法解决的问题。本文节选了LeetCode上两道组合的题目,并给出了使用试探-回溯策略的解法。
组合
题目描述
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
题目链接:https://leetcode.cn/problems/combinations
解答思路
与全排列类似,使用试探-回溯的策略。只是在调用回溯函数的时候有选择和不选两种情况。
代码
function combine(n: number, k: number): number[][] {
const result: number[][] = [];
const array = new Array(n).fill(0).map((_, i) => i + 1);
const res: number[] = [];
const backtrack = (cur: number) => {
// 抵达总数量,返推入结果
if (res.length === k) {
result.push([...res]);
return;
}
if (cur === n) return;
// 选择该数
res.push(array[cur]);
backtrack(cur + 1);
// 不选该数
res.pop();
backtrack(cur + 1);
}
// 从index为0的数开始计算
backtrack(0);
return result;
};
组合总和
题目描述
给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
题目链接:https://leetcode.cn/problems/combination-sum/description
解答思路
与上面一题类似,但是这里要以总和为target为结束条件,所以递归的时候要带上当前累积的总和(或者剩余的数值)作为待检验的对象。这里调用backtrack同样有两种情况,一种是选择当前数字(注意此时index不递增,以支持可重复选择的情况),另一种是不选当前数字。
代码
function combinationSum(candidates: number[], target: number): number[][] {
const result: number[][] = [];
const res: number[] = [];
const backtrack = (left: number, index: number) => {
if (index === candidates.length) return;
if (left === 0) {
// 剩余需要找的值为0,则找到一个结果
result.push([...res]);
return;
}
// 不选当前数字,index增加
backtrack(left, index + 1);
if (left - candidates[index] >= 0) {
// 选当前数字,index不变
res.push(candidates[index]);
backtrack(left - candidates[index], index);
res.pop();
}
}
backtrack(target, 0);
return result;
};
675

被折叠的 条评论
为什么被折叠?



