一、题目
给定一个 没有重复数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
二、思路
深度优先搜索(DFS) + 回溯
:
“回溯”可以理解为“状态重置”,就是回到上一步的状态。通常,我们要解决的问题是在一棵树上完成的,在这棵树上搜索需要的答案,一般使用深度优先搜索。
以数组 [1, 2, 3] 为例进行分析。
我们自己手写的话,只需要按顺序枚举每一位可能出现的情况,已经选择过的数字不能再使用,即
- 在枚举第一位的时候,有三种情况;
- 在枚举第二位的时候,前面已经用过的数字不能再用,此时只有两种情况;
- 在枚举第三位的时候,前面两个已经用过的数字不能再用,此时只有一种情况。
这样就能做到不重不漏,把可能的全排列都枚举出来,结果如下图所示:
如上图,将所有的结果写出来,用一个树形结构表示,就是这个问题的
解空间树
。每执行一次深度优先搜索,从树的根节点到叶节点的路径就是一个全排列。使用回溯法搜索全排列的解的过程如下图:
说明:
- 每一个节点表示全排列问题求解的不同阶段,也叫状态;
- 深度优先搜索的过程中,在搜索至叶节点时需要回溯,即返回上一步继续求解,这时的状态变量需要设置成为和先前一样;
- 因此,在回溯到上一层节点时,需要撤销上一次选择,即“状态重置”;
- 上图中,在 [1, 2] 处撤销 2 回到了 [1],又选择了 3 到达了状态 [1, 3],因为上一步撤销了 2,所以在这里才可以选择 2 从而达到状态 [1, 3, 2],这就是状态重置的意义。
三、代码
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
backTrack(list, new ArrayList<Integer>(), nums);
return list;
}
public void backTrack(List<List<Integer>> list, List<Integer> tempList, int[] nums){
if(tempList.size() == nums.length){
list.add(new ArrayList<>(tempList));
}else{
for(int i = 0; i < nums.length; i++){
// 已经使用过的数字就不能再用了,continue跳出本次循环,进行下一次循环
if(tempList.contains(nums[i]))
continue;
tempList.add(nums[i]);
backTrack(list, tempList, nums);
tempList.remove(tempList.size() - 1);// 回溯到上一步
}
}
}
}
版权声明:本文为weixin_45594025原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。