LeetCode热题(JS版)- 46. 全排列

76 阅读1分钟

题目

给定一个不含重复数字的数组 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]]

提示:

1 <= nums.length <= 6
-10 <= nums[i] <= 10
nums 中的所有整数 互不相同

思路:回溯法

本题可以用回溯法求解。回溯法是一种通过探索所有可能的候选解来找出所有的解的算法。如果候选解被确认不是一个解的话(或者至少不是最后一个解),回溯算法会通过在上一步进行一些变化把这个候选解排除掉。 具体实现上,可以通过递归找到所有可能的排列。每次递归中,从未使用的数字中选取一个数字,将其加入到当前排列的末尾,然后递归下一层。当排列中的数字数量达到原序列长度时,就找到了一个排列。如果当前排列的数字数量小于原序列长度,继续递归寻找下一个数字。

function permute(nums: number[]): number[][] {
    const len = nums.length;
    const result = [];
    const used = new Array(len).fill(false);

    // 回溯法
    const backtrack = (path: number[]) => {
        // 符合条件
        if(path.length === len) {
            result.push(path.slice());
            return;
        }

        // 挨个组合
        for(let i = 0; i < len; i++) {
            // 组合过的
            if(used[i]) continue;
            // 装进去
            used[i] = true;
            path.push(nums[i]);
            // 进行递归
            backtrack(path)
            // 吐出来
            used[i] = false;
            path.pop();
        }
    }

    backtrack([]);
    return result;
};

image.png

总结

  • 时间复杂度:O(n×n!)O(n \times n!),其中 nn 为原序列长度。其中 n!n! 为全排列的数量,需要遍历所有可能的排列,时间复杂度为 O(n!)O(n!)。而在每个排列中,需要遍历原序列中所有未使用的数字,时间复杂度为 O(n)O(n),因此总时间复杂度为 O(n×n!)O(n \times n!)
  • 空间复杂度:O(n)O(n),其中 nn 为原序列长度。递归调用 backtrack 函数时,需要使用 O(n)O(n) 的栈空间存储当前排列。同时,还需要使用 O(n)O(n) 的空间记录原序列中的数字是否已经在当前排列中使用过。因此总空间复杂度为 O(n)O(n)
  • 总结 本题是一道比较经典的回溯算法题目,对于初学者来说可以帮助他们更好地理解回溯算法。本题的解法可以应用到其他需要求解所有可能组合的题目中。