LeetCode 46. 全排列
题目描述
✅ 46. 全排列
题目:
给定一个不含重复数字的整数数组 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中的所有整数互不相同
思路分析
解法一:回溯(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
}
相似题目
| 题目 | 难度 | 考察点 |
|---|---|---|
| 31. 下一个排列 | 中等 | 排列规律 |
| 47. 全排列 II | 中等 | 回溯、去重 |
| 60. 排列序列 | 困难 | 数学、回溯 |
| 77. 组合 | 中等 | 回溯 |
| 39. 组合总和 | 中等 | 回溯 |
| 78. 子集 | 中等 | 回溯 |
| 90. 子集 II | 中等 | 回溯、去重 |
本博客所有文章除特别声明外,均采用
CC BY-NC-SA 4.0
许可协议,转载请注明出处!
