46. 全排列
查看题目中等
数组
高频
解法一:回溯
时间复杂度:O(n*n!) | 空间复杂度:O(n) | 推荐使用
动画演示
输入数组
代码实现
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
backtrack(nums, new ArrayList<>(), result);
return result;
}
// 时间复杂度:O(n*n!),空间复杂度:O(n)
public void backtrack(int[] nums, List<Integer> current, List<List<Integer>> result) {
if (current.size() == nums.length) {
result.add(new ArrayList<>(current));
return;
}
for (int num : nums) {
if (current.contains(num)) {
continue;
}
current.add(num);
backtrack(nums, current, result);
current.remove(current.size() - 1);
}
}
}时间复杂度:O(n*n!)
空间复杂度:O(n)
## 算法思路
本算法采用回溯递归的方式实现全排列:
1. **回溯思想**:通过不断尝试选择元素,构建排列,当排列长度达到原数组长度时,记录结果
2. **递归结构**:
- 基本情况:当前排列长度等于原数组长度,将当前排列添加到结果列表
- 递归情况:遍历所有未使用的元素,选择一个元素加入当前排列,然后递归处理剩余元素
3. **状态恢复**:在递归返回后,需要将当前选择的元素从排列中移除,标记为未使用,以便尝试其他选择
## 复杂度分析
- **时间复杂度**:O(n*n!)
- 每个排列需要O(n)的时间来复制到结果列表
- 总共有n!个排列
- 因此总时间复杂度为O(n*n!)
- **空间复杂度**:O(n)
- 递归调用栈的深度最多为n
- 当前排列的空间为O(n)
- 因此总空间复杂度为O(n)
## 核心步骤
1. 初始化结果列表和当前排列
2. 调用回溯函数,传入原始数组、当前排列和结果列表
3. 在回溯函数中:
- 如果当前排列长度等于原始数组长度,将当前排列添加到结果列表
- 否则,遍历所有元素:
- 如果元素未被使用,将其添加到当前排列
- 标记为已使用
- 递归调用回溯函数
- 回溯:从当前排列中移除该元素,标记为未使用
4. 返回结果列表