前端算法(39)

67 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

题目

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

输入: nums = [1,2,3]
输出: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

题目解析

思路一

我们这里使用递归进行实现,首先声明三个数组,分别是当前的路径,路径是否已经经过,和最后的结果数组。在使用递归,结束条件是当前路径数组的长度等于给定nums数组的长度,进入递归后,遍历nums数组,如果遍历到没有通过的数字,就放入路径数组,并把该数字标为已用,然后进入递归。在退出时将该数组从track中弹出,并标为未用,需要注意的是,在将track放入res时,因为是数组中放数组,数组中放引用类型需要特别注意放入一个又新地址的track副本,可以用Array.from或者concat,最后进行返回

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permute = function(nums) {
    var track = [];
    var used = new Array(nums.length).fill(false);
    var res = [];

    var backtrack = function(nums, track, used){
        if(track.length === nums.length){
            let item = track.concat();
            res.push(item);
            return;
        }
        for(let i = 0; i < nums.length; i++){
            if(used[i]){
                continue;
            }
            track.push(nums[i]);
            used[i] = true;
            backtrack(nums, track, used);
            track.pop();
            used[i] = false;
        }

    }
    backtrack(nums, track, used);
    return res;
};

思路二

我们这里采用递归方式,每轮递归进行两次循环。记下初始的上一次结果preResult为[[]],结合初始数组nums,每次递归内,创建一个新数组res,对preResult和nums执行两个循环,将结果放入res。再递归的把res作为下一次的preResult传入permute(nums,res)。终止条件为判断到preResult中任何一个元素长度等于nums的长度。此时得到每轮的res是对于nums的重复排列,需要额外循环体内需做一个重复判断,最后得到的便是题目中的非重复的全排列了

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permute = function(nums,preResult=[[]]) {
    if(preResult[0].length===nums.length)return preResult
    const res=[]
    for(let i=0;i<preResult.length;i++){
        for(let j=0;j<nums.length;j++){
            if(!preResult[i].includes(nums[j])){
                res.push([...preResult[i],nums[j]])
            }
        }
    }
    return permute(nums,res)
};