剪枝和回溯是解决决策问题时非常有效的技巧。在很多情况下,需要搜索所有的可能解决方案以找到最优解或满足某些条件的解决方案,但搜索所有的可能性是非常耗时的。通过回溯和剪枝,可以有效地减少搜索空间。
回溯
function backtrack(list, tempList, nums, start) {
// 添加到结果集
list.push([...tempList]);
for (let i = start; i < nums.length; i++) {
// 做选择
tempList.push(nums[i]);
// 继续递归填下一个数
backtrack(list, tempList, nums, i + 1);
// 撤销选择
tempList.pop();
}
}
剪枝
在回溯算法中,如果发现已有的部分序列不可能产生正确的结果,可以停止进一步的搜索,这就是剪枝。
常见题型
- 组合问题:如,给定一个无重复元素的数组,找到所有可能的组合。
- 排列问题:例如,给定一个数字集合,返回其所有可能的排列。
- N皇后问题:在NxN的棋盘上放置N个皇后,使得它们不能相互攻击。
- 数独:填写一个9x9的数独,只需要按照一些规则填数字1-9。
- 子集问题:例如,给定一组不含重复元素的整数,返回所有可能的子集。
- 括号生成:给定n对括号,编写一个函数生成所有的有效括号组合。
- 单词搜索:给定一个二维网格和一个单词,找出该单词是否存在于网格中。
对于剪枝的实践来说,关键是如何根据已有的部分序列,快速地判断其后续是否能构成一个解,如果不能就进行剪枝。这通常需要根据具体问题来进行设计。