LeetCode LCR 083. 全排列

题目描述

LCR 083. 全排列

思路分析

解法一:回溯(used 标记)(推荐)

核心思路

  • 维护一个 used 数组表示数字是否已使用。
  • 每次从未使用的数字中选择一个加入路径,递归构造。
  • 当路径长度等于数组长度时收集结果。

复杂度分析

  • 时间复杂度:O(n * n!),其中 n 表示数组长度。
  • 空间复杂度:O(n),其中 n 表示递归栈深度与 used 数组大小。
// 回溯 + used 标记
class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        boolean[] used = new boolean[nums.length];
        backtrack(nums, used, new ArrayList<>(), res);
        return res;
    }

    private void backtrack(int[] nums, boolean[] used, List<Integer> path, List<List<Integer>> res) {
        if (path.size() == nums.length) {
            res.add(new ArrayList<>(path));
            return;
        }

        for (int i = 0; i < nums.length; i++) {
            if (used[i]) {
                continue;
            }
            used[i] = true;
            path.add(nums[i]);
            backtrack(nums, used, path, res);
            path.remove(path.size() - 1);
            used[i] = false;
        }
    }
}
// 回溯 + used 标记
func permute(nums []int) [][]int {
	var res [][]int
	used := make([]bool, len(nums))
	path := make([]int, 0, len(nums))

	var backtrack func()
	backtrack = func() {
		if len(path) == len(nums) {
			copyPath := append([]int{}, path...)
			res = append(res, copyPath)
			return
		}
		for i := 0; i < len(nums); i++ {
			if used[i] {
				continue
			}
			used[i] = true
			path = append(path, nums[i])
			backtrack()
			path = path[:len(path)-1]
			used[i] = false
		}
	}

	backtrack()
	return res
}

解法二:回溯(原地交换)

核心思路

  • 从位置 first 开始,依次将 nums[first] 与后面元素交换。
  • 交换后递归处理 first + 1,回溯时再交换回来。
  • 不需要 used 数组,节省空间。

复杂度分析

  • 时间复杂度:O(n * n!),其中 n 表示数组长度。
  • 空间复杂度:O(n),其中 n 表示递归栈深度。
// 回溯 + 原地交换
class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        backtrack(nums, 0, res);
        return res;
    }

    private void backtrack(int[] nums, int first, List<List<Integer>> res) {
        if (first == nums.length) {
            List<Integer> path = new ArrayList<>();
            for (int num : nums) {
                path.add(num);
            }
            res.add(path);
            return;
        }

        for (int i = first; i < nums.length; i++) {
            swap(nums, first, i);
            backtrack(nums, first + 1, res);
            swap(nums, first, i);
        }
    }

    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}
// 回溯 + 原地交换
func permute(nums []int) [][]int {
	var res [][]int

	var backtrack func(int)
	backtrack = func(first int) {
		if first == len(nums) {
			copyPath := append([]int{}, nums...)
			res = append(res, copyPath)
			return
		}
		for i := first; i < len(nums); i++ {
			nums[first], nums[i] = nums[i], nums[first]
			backtrack(first + 1)
			nums[first], nums[i] = nums[i], nums[first]
		}
	}

	backtrack(0)
	return res
}

相似题目

题目 难度 考察点
47. 全排列 II 中等 回溯
77. 组合 中等 回溯
39. 组合总和 中等 回溯
40. 组合总和 II 中等 回溯
78. 子集 中等 回溯
90. 子集 II 中等 回溯
本文作者:
本文链接: https://hgnulb.github.io/blog/2026/81384266
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!