「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战」
前言
每天至少一道算法题,死磕算法
题目
这是leetcode上的第46到题目46. 全排列
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例 1:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
分析
第一步:从题目中提取关键字
- 1.给定一个不含重复数字的数组 nums ,那我们先判断是否为空
- 2.排列组合的题目我们高中都学过,那题目中的这个例子,套用公式n!,也就是3!=321,一共6种答案,我们把这些答案先画出来,一步一步分析
我们先排列出第一层的答案,1,2,3,1下面可以分出2,3,因为1已经被用掉了,2下面只能分出3,因为1,2都已经用掉了,此时一条答案就出来了,我们是如何判断答案出来了,因为已经够三个数了,不能超出题目给出的数字个数。
通过我们画出的图来看,这不就是一颗树么,多叉树,要想得到答案这不进行一个先序遍历不就可以了,因为每一次遍历到底部就会出来一个答案,先序遍历也就是我们常说的回溯算法
既然要使用回溯算法,那么需要搞清三个东西
- 1.路径:也就是已经做出的选择
- 2.选择列表:也就是你当前可以做的选择
- 3.结束条件:也就是无法在做选择的条件
框架
弄懂我们要使用回溯算法以后,然后在说一下回溯算法的框架,框架就相当于公式呀,要理解,要背的哈,这里画重点
result = [];
let backTrack = function(选择列表,路径){
if(满足条件){
result.push(路径);
return;
}
for(选择 in 选择列表){
添加到路径中
backTrack(选择列表,路径)
从路径中撤销
}
}
关于这个从路径中撤销我们详细说一下,比如
第一排,我们把3加入到路径以后,在执行backTrack,发现满足条件了,那么return了,然后把3从路径中pop掉,然后又一个backTrack执行完毕,然后2从track中pop出来,此时track里面只剩1了,这种不断网上回退的方法,我们就称为回溯,这也是回溯的由来
接下来我们就开始写题把
// 要返回的结果
let result = [];
// 主函数
var permute = function(nums) {
// 定义路径
let track = [];
// 传入选择列表和路径,回溯是要使用递归的
backTrack(nums,track);
return result;
};
let backTrack = function(nums,track){
// 结束条件
if(nums.length===track.length){
// 此处之所以要用slice,因为track是数组,每次把track放入数组,那么他们的地址都一样,经过不断pop以后,你会发现你存入的都是空数组,所以要使用slice,因为他会返回一个新数组
result.push(track.slice());
return;
}
// 选择路径
for(let i=0;i<nums.length;i++){
// 筛选没有放入路径的选择
if(track.includes(nums[i])){
continue;
}
// 向路径中添加选择
track.push(nums[i]);
// 选择下一层的路径
backTrack(nums,track);
// 从路径撤销选择
track.pop(nums[i]);
}
}
总结
上面的讲解虽然讲完了,大家一定要好好会为一下,把遍历的整个流程在脑子里面过一遍