
解题思路:
- 递归参数: 给定数组 nums、结果集 result、当前路径 path、标记数组 used。
- 递归过程:
- 当路径 path 的大小等于 nums 长度时,说明找到一个全排列,加入结果集。
- 遍历 nums,对于每个未被选中的元素,标记为已使用,加入路径,递归处理后续选择。
- 递归返回后,撤销选择(回溯),继续尝试其他可能性。
Java代码:
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
boolean[] used = new boolean[nums.length];
backtrack(nums, result, path, used);
return result;
}
private void backtrack(int[] nums, List<List<Integer>> result, List<Integer> path, boolean[] used) {
if (path.size() == nums.length) {
result.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, result, path, used);
path.removeLast();
used[i] = false;
}
}
}
复杂度分析:
- 时间复杂度: O(nn!)。生成所有排列需要 n! 次操作,每次生成需 O(n) 时间复制数组或列表。
- 空间复杂度: O(n)(递归栈)+ O(nn!)(结果存储)。递归深度为 n,结果集存储所有排列。

解题思路:
- 递归参数: 给定数组 nums、结果集 result、当前路径 path、当前起始索引 start。
- 递归过程:
- 每次进入递归时,将当前的路径加入结果集(因为路径的任何状态都是一个有效子集)。
- 遍历 nums,从 start 开始遍历数组,依次将元素加入路径,递归处理后续选择。
- 递归返回后,撤销选择(回溯),继续尝试其他可能性。
Java代码:
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
backtrack(nums, result, path, 0);
return result;
}
private void backtrack(int[] nums, List<List<Integer>> result, List<Integer> path, int start) {
result.add(new ArrayList<>(path));
for (int i = start; i < nums.length; i++) {
path.add(nums[i]);
backtrack(nums, result, path, i + 1);
path.remove(path.size() - 1);
}
}
}
复杂度分析:
- 时间复杂度: O(n
2
n
2^n
2n)。每个元素都有选或不选两种选择,共生成
2
n
2^n
2n 个子集。每次生成子集需 O(n) 时间复制路径到结果集。
- 空间复杂度: O(
2
n
2^n
2n)(结果存储)+ O(n)(递归栈)。