leetcode 46 全排列 JavaScript

leetcode 46 全排列 JavaScript
在这里插入图片描述
思路:
全排列的主要思想是回溯,递归过程使用的是dfs,只不过在dfs的过程中会涉及到对已使用的数进行标记,标记后递归,再把标记清除的一个过程
add:
时隔多个月再次回顾,毕竟dfs 回溯,是本人弱项
1、首先考虑一下什么时候结束一次循环 => 填满一次nums长度的数组
比如nums是[1,2,3], 自己循环时填的数组path为[],完成一次填满path的操作
2、填数组时应该做什么操作
(1)判断是否使用过该数字,如已使用,continue,因为path里的数不能重复
(2)如果没使用过,push进path中,并标记该数字已使用
(3)递归,同时考虑递归的结束判断 =>当path填满nums长度之后(也就是1提到的),将填满的path加到最后返回结果数组res中,之后结束本次递归
(4)回溯,最难懂的一步
为了搞懂这个,我从递归流程中分析了一遍
dfs([1])->dfs([1,2])->dfs([1,2,3])->return 此时used=1,2,3 同时由于满足递归条件,res得到了首个组装完成的path 也就是目前res=[[1,2,3]],此时path=[1,2,3]的递归已经停止
轮到path=[1,2]的递归执行下一步了,也就是path.pop(),同时used[2] = false 此时used=1,2,path=[1],
此时到下一个循环,也就是3,所以会产生[1,3]的path继续递归 最终得到[1,3,2]递归结束
轮到path=[1]执行pop,used[1] = false,此时path=[],used也清空了
ok第一次for循环结束,轮到2先进场…
推算到这里,如果没理解错的话,回溯其实就是为下一次循环清空要复用的path和used,最主要的还是第(3)步递归的流程
妙,一看就会,一写就废 g

代码如下

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permute = function(nums) {
    const res = [];
    const used = {};

    function dfs(path) {
        if (path.length == nums.length) { // 递归完成
            res.push([...path]); // 拷贝path
            return;                 
        }
        for (let num of nums) {
            if (used[num]) continue; // 使用过该数
            path.push(num);         // 放入path
            used[num] = true;       // 已使用
            dfs(path);              // 选了数之后递归
            path.pop();             // 回溯上一步 同时要把刚刚用了的数设为false
            used[num] = false;      // 重设为未使用
        }
    }

    dfs([]);
    return res;
};

这里涉及到一个path的拷贝,因为传入的参数是引用数据类型,如果不进行拷贝,那么path始终指向堆中同一个地址空间,即便后面push到res中,res里面实际上存的也是它在栈中的引用,只要被修改,对应的值全部都改变,最后会发现结果全为空数组。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值