46. 全排列
有了前面回溯的基础(组合,切割,子集等)之后,做这道题就相对简单了。
我们主要是来看一下排列问题和组合问题的区别在哪里?
1. 前面的组合问题中,我们是要有一个startIndex数组的,它是用来判断下一层递归是从那个树开始取的,避免取到一些重复的组合,比如【1,2,3】 【2,1,3】,但是在排列问题中这样不是同一个排列。
2.在排列问题中的关键是取过元素之后在递归中就不需要重复取了,比如只看最左外侧,如果不判断,取了1,然后又能取的话就出现了【1,1】。所以需要有一个used数组来判断取过了哪些元素。
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
int n = nums.length;
boolean[] flag = new boolean[n];
backtrack(nums,n,flag);
return res;
}
public void backtrack(int[] nums,int n,boolean[] flag){
if(path.size()==n){
res.add(new ArrayList(path));
return;
}
for(int i=0;i<n;i++){
if(flag[i]==true){
continue;
}
path.add(nums[i]);
flag[i]=true;
backtrack(nums,n,flag);
flag[i]=false;
path.remove(path.size()-1);
}
}
}
47. 全排列 II
这个题和前面的非递减子序列去重相似,不能对它进行排序,因为排序之后会造成出现不想要的结果,所以不能像之前的组合等问题一样用used数组,这个时候可以在树层做一个set,来记录树层中是否有重复。
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> permuteUnique(int[] nums) {
int n = nums.length;
boolean[] flag = new boolean[n];
backtrack(nums,n,flag);
return res;
}
public void backtrack(int[] nums,int n,boolean[] flag){
if(path.size()==n){
res.add(new ArrayList(path));
return;
}
Set<Integer> unique = new HashSet<>();
for(int i=0;i<n;i++){
if(flag[i]==true){
continue;
}
if(unique.contains(nums[i])){
continue;
}
unique.add(nums[i]);
path.add(nums[i]);
flag[i]=true;
backtrack(nums,n,flag);
flag[i]=false;
path.remove(path.size()-1);
}
}
}