在做过很多回溯算法的题,总结下思路(简称回溯算法三步曲):
- 确定递归函数参数和返回值;
- 找出递归出口;
- 写出单层搜索的逻辑; 或者是
- 「路径」:记录做出的选择。
- 「选择列表」:通常而言,用数组存储可以选择的操作。
- 「结束条件」:一般而言,就是递归的结束点,也就是搜索的结束点。 回溯算法还可以总结为一句话:
回溯法可以理解成为通过选择不同的岔路口,来寻找目的地,一个岔路口一个岔路口的去尝试找到目的地,如果走错了路的话,继续返回到上一个岔路口的另外一条路,直到找到目的地。
回溯算法大致代码思路如下:
result = []
function backtrack(路径, 选择列表) {
if('满足结束条件') { // 这里就是对答案做更新,依据实际题目出发
result.push(路径)
return
} else {
for(let i = 0; i < 选择列表.length; i++) { // 对一个选择列表做相应的选择 做选择
backtrack(路径, 选择列表) // 既然是回溯算法,那么在一次分岔路做完选择后
// 需要回退我们之前做的操作 撤销选择
}
}
}
下面是个回溯算法的例子(力扣第77道算法题)#### 77.:
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
/**
* @param {number} n
* @param {number} k
* @return {number[][]}
*/
var combine = function(n, k) {
let result = [] //二维数组,即最后的结果集
let path = [] //一维数组
const combineHelper = (n, k, startIndex) => { //startIndex这个入参, 每次递归都加一
if (path.length === k) { //递归算法出口
result.push([...path])
return
}
for (let i = startIndex; i <= n - (k - path.length) + 1; ++i) {
path.push(i)
combineHelper(n, k, i + 1)
path.pop() //为了返回到上一层
}
}
combineHelper(n, k, 1)
return result
};