持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第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]]
思路
- 显然这是一个需要穷举探索所有可能的解
- 回溯法:采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。
- 回溯法在部分题目中,可以利用「剪枝」手法来优化时间复杂度,减少无用的运算
解题方法
- 数组转成list
- 递归(当前处理位置,总长度,结果,输出)
- 递归 - 首先处理极端情况,当start = n时结束递归
- 递归 - 将start和n之间的元素挨个与start进行交换,以达到穷举的目的,并且小于start的数都是被用过的,大于start的数是后续递归需要的
- 递归 - 下一层底柜
- 递归 - 回溯还原output数组,供下一次遍历使用
复杂度
-
时间复杂度: O(n×n!)
- 时间复杂度O(n) 首先遍历每一个元素,然后依赖于调用递归的次数,n(n-1)....1
-
空间复杂度: O(n)
- 空间复杂度,可以利用数组交换来节省至O(n)
Code
class Solution {
public List<List<Integer>> permute(int[] nums) {
// 结果
List<List<Integer>> res = new ArrayList<>();
List numList = new ArrayList();
// 全部存到list中
int n = nums.length;
for (int i = 0; i < n; i++) {
numList.add(nums[i]);
}
recursion(0,n,res,numList);
return res;
}
/**
* 递归
*/
public void recursion(int start,int n,List res,List output){
if(start == n){
res.add(new ArrayList<>(output));
}
int i = start;
// 穷举 按序添加后再放回
while (i < n){
Collections.swap(output,start,i);
recursion(start + 1,n,res,output);
// 复原数组,并i+1
Collections.swap(output,start,i++);
}
}
}
Problem: 46. 全排列