js算法题解(第二十天)---leetcode-46. 全排列

487 阅读3分钟

「这是我参与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种答案,我们把这些答案先画出来,一步一步分析

图片.png

我们先排列出第一层的答案,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(选择列表,路径)
        从路径中撤销    
    }
}

关于这个从路径中撤销我们详细说一下,比如

图片.png

第一排,我们把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]);
    }
}

总结

上面的讲解虽然讲完了,大家一定要好好会为一下,把遍历的整个流程在脑子里面过一遍

参考