返回
巧用回溯法,轻松解决「前端刷题」40. 组合总和 II
前端
2023-10-13 23:07:43
简介
「前端刷题」40. 组合总和 II 是一道经典的组合问题。给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组。这些组可以包含重复的元素。
例如,给定数组 candidates = [10, 1, 2, 7, 6, 1, 5] 和目标数 target = 8,所有满足要求的组合有:
[1, 7]
[1, 2, 5]
[2, 6]
[1, 1, 6]
回溯法概述
回溯法是一种用于解决组合问题的通用算法。它通过系统地搜索所有可能的解决方案来找到满足特定条件的所有解。回溯法的工作原理是:
- 从一个初始状态开始,并生成所有可能的下一状态。
- 对每个下一状态,重复步骤 1,直到达到最终状态或无法生成更多下一状态。
- 如果达到最终状态,则保存该状态并回溯到上一个状态。
- 如果无法生成更多下一状态,则回溯到上一个状态。
回溯法解决组合总和 II
为了使用回溯法解决组合总和 II 问题,我们可以按照以下步骤进行:
- 将候选数组 candidates 排序,以便于查找重复的元素。
- 定义一个回溯函数,该函数接受三个参数:当前状态、当前和以及候选数组。
- 在回溯函数中,首先检查当前和是否等于目标和。如果是,则将当前状态保存到结果列表中。
- 否则,依次考虑候选数组中的每个元素。对于每个元素,如果当前和加上该元素小于目标和,则将该元素添加到当前状态并调用回溯函数。
- 回溯到上一个状态时,将最后一个元素从当前状态中删除。
JavaScript 代码实现
/**
* 给定一个数组 candidates 和一个目标数 target,找出 candidates 中所有可以使数字和为 target 的组。
* 这些组可以包含重复的元素。
*
* @param {number[]} candidates 候选数组
* @param {number} target 目标数
* @return {number[][]} 所有满足要求的组合
*/
const combinationSum2 = (candidates, target) => {
// 对候选数组进行排序,以便于查找重复的元素
candidates.sort((a, b) => a - b);
// 定义一个结果列表,用于保存所有满足要求的组合
const result = [];
// 定义一个回溯函数
const backtrack = (combination, currentSum, start) => {
// 如果当前和等于目标和,则将当前组合保存到结果列表中
if (currentSum === target) {
result.push([...combination]);
return;
}
// 如果当前和大于目标和,则回溯到上一个状态
if (currentSum > target) {
return;
}
// 依次考虑候选数组中的每个元素
for (let i = start; i < candidates.length; i++) {
// 如果当前元素等于上一个元素,则跳过
if (i > start && candidates[i] === candidates[i - 1]) {
continue;
}
// 将当前元素添加到当前组合中
combination.push(candidates[i]);
// 调用回溯函数,并更新当前和和起始索引
backtrack(combination, currentSum + candidates[i], i + 1);
// 从当前组合中删除最后一个元素
combination.pop();
}
};
// 调用回溯函数,并传入一个空组合、0 和 0
backtrack([], 0, 0);
// 返回结果列表
return result;
};
总结
回溯法是一种强大的算法,可以用于解决许多组合问题。通过使用回溯法,我们可以系统地搜索所有可能的解决方案,并找到满足特定条件的所有解。在本文中,我们使用回溯法解决了组合总和 II 问题。我们对候选数组进行排序,以方便查找重复的元素。然后,我们定义了一个回溯函数,该函数接受三个参数:当前状态、当前和以及候选数组。在回溯函数中,我们首先检查当前和是否等于目标和。如果是,则将当前状态保存到结果列表中。否则,我们依次考虑候选数组中的每个元素。对于每个元素,如果当前和加上该元素小于目标和,则将该元素添加到当前状态并调用回溯函数。回溯到上一个状态时,我们将最后一个元素从当前状态中删除。
希望本文能帮助您理解回溯法并解决更多组合问题。如果您有任何问题或建议,请随时提出。