排列和组合最大的区别就是组合不讲究顺序,只要数组中元素相同即是一个组合,而排列即使是数组中元素相同 ,只要元素的顺序不同,就是一种新的排列。
于是,之前在组合问题中使用的startindex在排列中就失效了,排列不需要排除在同一个树层中之前使用过的元素。那要如何解决在递归中遍历不取到重复元素呢?(同树层中有for循环i++,不会一直取同一个元素,只有递归才有可能)
这里使用used数组来进行标记,每取一个元素,在相应的used数组位置置1,证明该元素已取过。在递归中的从数组头开始取的时候就不会再取到上一次取过的元素。
去重的两种方法:1.数组可以排序的情况下,同样使用used数组标记来进行去重。
2.在数组不可以排序和可以排序的情况下,都可以使用HashSet来进行去重
这一题就是在数组不可以排序的情况下,求组合递增子集。使用set。在代码中,每一层递归都new一个新的set,用来保证当前层不使用重复元素进行组合。所以在最后的回溯中也不需要再移除set中的元素。
class Solution {
List<List<Integer>> res=new ArrayList();
List<Integer> path=new ArrayList();
public List<List<Integer>> findSubsequences(int[] nums) {
backtracking(nums,0);
return res;
}
public void backtracking(int[] nums,int startindex){
if(path.size()>=2){
res.add(new ArrayList(path));
}
if(path.size()>=nums.length){
return;
}
Set<Integer> set=new HashSet();//每一层都是一个新的set,用来保证当前层树层去重
for(int i=startindex;i<nums.length;i++){
if(!path.isEmpty()&&(nums[i]<path.get(path.size()-1))||set.contains(nums[i])){
continue;
}
path.add(nums[i]);
set.add(nums[i]);
backtracking(nums,i+1);
path.remove(path.size()-1);
}
}
}
class Solution {
List<List<Integer>> res=new ArrayList();
List<Integer> path=new ArrayList();
boolean[] used;
public List<List<Integer>> permute(int[] nums) {
used=new boolean[nums.length];
Arrays.fill(used,false);
backtracking(nums,used);
return res;
}
public void backtracking(int[] nums,boolean[] used){
if(path.size()>=nums.length){
res.add(new ArrayList(path));
return;
}
for(int i=0;i<nums.length;i++){
if(used[i]==true){
continue;
}
path.add(nums[i]);
used[i]=true;
backtracking(nums,used);
path.remove(path.size()-1);
used[i]=false;
}
}
}
这一题就是全排列和去重的结合版。使用上面两题的方法结合就能解决
class Solution {
List<List<Integer>> res=new ArrayList();
List<Integer> path=new ArrayList();
boolean[] used;
public List<List<Integer>> permuteUnique(int[] nums) {
used =new boolean[nums.length];
Arrays.fill(used,false);
backtracking(nums,used);
return res;
}
public void backtracking(int[] nums,boolean[] used){
if(path.size()>=nums.length){
res.add(new ArrayList(path));
return;
}
Set<Integer> set=new HashSet();
for(int i=0;i<nums.length;i++){
if(used[i]==true||set.contains(nums[i])){
continue;
}
path.add(nums[i]);
set.add(nums[i]);
used[i]=true;
backtracking(nums,used);
path.remove(path.size()-1);
used[i]=false;
}
}
}