给定一个不含重复数字的数组
nums
,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案
回溯法:
回溯法 采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况:
- 找到一个可能存在的正确的答案;
- 在尝试了所有可能的分步方法后宣告该问题没有答案
具体思路:
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
int[] used = new int[nums.length];
order(res,nums,new ArrayList<Integer>(),used);
return res;
}
private void order(List<List<Integer>> res,int[] nums,ArrayList<Integer> tmp, int[] used){
if(tmp.size() == nums.length){
res.add(new ArrayList(tmp));
return;
}
for(int i = 0;i < nums.length;i++){
if(used[i] == 1){
continue;
}
used[i] = 1;
tmp.add(nums[i]);
System.out.println(" 递归之前 => " + path);
order(res,nums,tmp,used);
used[i] = 0;//回溯
tmp.remove(tmp.size()-1);//回溯
System.out.println("递归之后 => " + path);
}
}
}
控制台输出
递归之前 => [1]
递归之前 => [1, 2]
递归之前 => [1, 2, 3]
递归之后 => [1, 2]
递归之后 => [1]
递归之前 => [1, 3]
递归之前 => [1, 3, 2]
递归之后 => [1, 3]
递归之后 => [1]
递归之后 => []
递归之前 => [2]
递归之前 => [2, 1]
递归之前 => [2, 1, 3]
递归之后 => [2, 1]
递归之后 => [2]
递归之前 => [2, 3]
递归之前 => [2, 3, 1]
递归之后 => [2, 3]
递归之后 => [2]
递归之后 => []
递归之前 => [3]
递归之前 => [3, 1]
递归之前 => [3, 1, 2]
递归之后 => [3, 1]
递归之后 => [3]
递归之前 => [3, 2]
递归之前 => [3, 2, 1]
递归之后 => [3, 2]
递归之后 => [3]
递归之后 => []
输出 => [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
使用Deque<Integer> path = new ArrayDeque<>()来添加某个答案的代码:
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
if(nums.length == 0){
return res;
}
Deque<Integer> path = new ArrayDeque<>();
boolean[] used = new boolean[nums.length];
dfs(nums,path,res,used);
return res;
}
private void dfs(int[] nums, Deque<Integer> path, List<List<Integer>> res, boolean[] used) {
if(path.size() == nums.length){
res.add(new ArrayList<>(path));
return;
}
for(int i = 0; i < nums.length;i++){
if(used[i]){
continue;
}
path.addLast(nums[i]);
used[i] = true;
dfs(nums,path,res,used);
path.removeLast();
used[i] = false;
}
}
}