LeetCode 46 Permutations (Tag:Array Difficulty:Medium)

245 阅读2分钟

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

前言

关于 LeetCode 数组类型题目的相关解法,可见LeetCode 数组类型题目做前必看,分类别解法总结了题目,可以用来单项提高。觉得有帮助的话,记得多多点赞关注哦,感谢!

题目描述

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

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

示例 2:
输入:nums = [0,1]
输出:[[0,1],[1,0]]

示例 3:
输入:nums = [1]
输出:[[1]]

链接:leetcode-cn.com/problems/pe…

题解

这道题是一道典型的dfs+回溯模式题. 在LeetCode 数组类型题目做前必看文中, 有个排列dfs的模版, 直接套过来就可以了. 我们先直接给出代码

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permute = function(nums) {
    const n = nums.length
    let used = new Array(n).fill(0)
    let ans = []
    
    const dfs = (nums, d, n, used, curr, ans) => {
        if (d === n) {
            ans.push([...curr])
            return
        }
        
        for (let i = 0; i < n; ++i) {
            if (used[i]) continue
            used[i] = 1
            curr.push(nums[i])
            dfs(nums, d+1, n, used, curr, ans)
            // 恢复原样
            used[i] = 0
            curr.pop()
        }
    }
    
    dfs(nums, 0, n, used, [], ans)
    return ans
};

代码中主要部分是 dfs 这个函数, 这个函数有几个重要的点.
一个是递归终止条件: d === n, 其中 d 代表 curr 数组的元素个数, n 代表 nums 数组的元素个数, 当 nums 所有的元素都添加到了 curr 数组中时, 就表示其中的一个排列被找到了, 然后 push 进 ans 数组中.
一个是 used 数组: used 数组被用来标记 nums[i] 是否已经被使用过了, 1 表示使用过了, 0 表示未使用过. 因为我们每次都需要从 i = 0 位置开始遍历(为了找出所有组合), 所以 used 数组必须要存在.
另外的点就是, 在一次递归dfs之后, 我们必须要将之前添加的 nums[i] 从 curr 中 pop 出去, 以及将 used[i] 置为 0, 这样做就不会影响后面的递归, 这一步称之为回溯. 也就是回到之前的状态. 对于数组 [1, 2, 3], 对该数组的求解过程可以看下图, 本图来源于 liweiwei1419 image.png

时间复杂度: 对于长度为 n 的数组, 其一共有 n! 种组合, 而求出每种组合都需要遍历一遍数组, 故时间复杂度为 O(n * n!)