1. 回溯算法的基本思想
回溯算法,简单来说就是就是解决一颗决策树,这里拿leetcode 46 全排列问题为例子:
该问题是需要我们返回一个无重复数字的数组的全排列。解决这个问题,我们回想中学时候的排列组合,例如我们需要对[1, 2, 3]进行全排列,我们会首先选择1,然后对23排列,然后是选2开始,选3开始诸如此类。如果画成图示,如下:
2. 回溯算法的细节
上面这幅图就是我们手动操作排列组合的框架,而回溯算法就是在这个树状图的基础上加上了选择,和选择回退,使用递归进行整个树状图的遍历从而得到结果。 比如,参考下图,我们现在站在1这个节点,我们之前已经选择过了1,我们剩下的选择是2和3,我们可以做出任一选择,直到我们的选择列表为空,于是我们回撤一个选择,继续递归的过程。
那我们现在开始来做leetcode 46,首先明确我们需要知道
- 我们已经做出的选择,也就是路径
- 接下来可以做的选择,选择列表
- 回撤一个选择,结束条件
/**
* @param {number[]} nums
* @return {number[][]}
*/
var permute = function(nums) {
};
第一步: 定义我们的结果res数组,定义我们的路径track数组,定义我们的used数组
这里我们使用used数组,去排除我们已经做出的选择
var permute = function(nums) {
let res = []
let track = []
let used = new Array(nums.length).fill(false)
};
第二步:定义我们的traverse函数,接收track, nums,used数组;
var permute = function(nums) {
let res = []
let track = []
let used = new Array(nums.length).fill(false)
function backTraverse(nums, track, used) {
// 如前述,我们需要判断结束条件
if (nums.length === track.length) {
res.push(track.slice())
return;
}
// 遍历树
for (let i = 0; i < nums.length; i++) {
if (used[i]) {
continue;
}
// 做选择
track.push(nums[i])
used[i] = true
// 递归
backTraverse(nums, track, used)
// 回撤
track.pop()
used[i] = false
}
}
backTraverse(nums, track, used)
return res
};