题目
   
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
示例 1:
输入:nums = [1,1,2]
输出:
[[1,1,2],
 [1,2,1],
 [2,1,1]]
示例 2:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
 
提示:
1 <= nums.length <= 8
-10 <= nums[i] <= 10
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutations-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    
    
    想法
   
    这题和46题及其相似,唯一不同的是,可以含有重复元素,所以我先把代码写下来,和46题代码大致不变,唯一有区别的就再去重问题上,怎么样去重是这类问题需要关注的地方,这次我没想到怎么去重,所以用了hashset,hashset虽然能去重,但是啊,这个效率低的很。
    
    所以先把代码写上吧:
   
class Solution {
    List<Integer> list = new ArrayList<>();
    List<List<Integer>> res = new ArrayList<>();
   // Set<List<Integer>> set = new HashSet<>();
    public List<List<Integer>> permuteUnique(int[] nums) {
        boolean[] check = new boolean[nums.length];
        Arrays.sort(nums);
        dfs(nums,check);
        Set set = new HashSet(res);
        res = new ArrayList<>(set);
        return res;
    }
    public void dfs(int[] nums,boolean[] check)
    {
        if(nums.length == list.size())
        {
            
            res.add(new ArrayList<>(list));
            return;
        }
         for(int i = 0 ; i< nums.length;i++)
        {
            if(check[i]==true) continue;
          
            check[i] =true;
            list.add(nums[i]);
            dfs(nums,check);
            check[i] = false;
            list.remove(list.size()-1);
        }
    }
}
    这个结果也比较垫底了。
    
    
    
    解决去重问题,就要去掉set还要另寻剪枝的好方法。
    
    我在尝试过程中找到剪枝:
   
if(i>0&&nums[i]==nums[i-1]&check[i-1]==true) continue;
在for循环中加入这一行,就可以,不用再用set。
class Solution {
    List<Integer> list = new ArrayList<>();
    List<List<Integer>> res = new ArrayList<>();
   // Set<List<Integer>> set = new HashSet<>();
    public List<List<Integer>> permuteUnique(int[] nums) {
        boolean[] check = new boolean[nums.length];
        Arrays.sort(nums);
        dfs(nums,check);
    
        return res;
    }
    public void dfs(int[] nums,boolean[] check)
    {
        if(nums.length == list.size())
        {
            
            res.add(new ArrayList<>(list));
            return;
        }
         for(int i = 0 ; i< nums.length;i++)
        {
            if(i>0&&nums[i]==nums[i-1]&check[i-1]==true) continue;
            if(check[i]==true) continue;
          
            check[i] =true;
            list.add(nums[i]);
            dfs(nums,check);
            check[i] = false;
            list.remove(list.size()-1);
        }
    }
}
    但是呢,这个效率还是不是很高。
    
    
    
    再寻找快速的方法,在评论中找到,当你回溯的时候,遇到重复的下一个元素可以跳过。
   
 while(i<nums.length-1&&nums[i]==nums[i+1]) i++;
重新写:
class Solution {
    List<Integer> list = new ArrayList<>();
    List<List<Integer>> res = new ArrayList<>();
   // Set<List<Integer>> set = new HashSet<>();
    public List<List<Integer>> permuteUnique(int[] nums) {
        boolean[] check = new boolean[nums.length];
        Arrays.sort(nums);
        dfs(nums,check);
    
        return res;
    }
    public void dfs(int[] nums,boolean[] check)
    {
        if(nums.length == list.size())
        {
            
            res.add(new ArrayList<>(list));
            return;
        }
         for(int i = 0 ; i< nums.length;i++)
        {
            if(!check[i]){
            
            check[i] =true;
            list.add(nums[i]);
            dfs(nums,check);
            check[i] = false;
            list.remove(list.size()-1);
            while(i<nums.length-1&&nums[i]==nums[i+1]) i++;
            }
            
            
          
           
        }
    }
}
    本次快了很多。
    
     
   
    
    
    总结
   
    之前那个排列组合就有个不重复的问题,不重复要是用set就回很慢,所以需要找到某个条件让重复去掉,所以一般就是排序后找到相邻的元素,想办法越过这个相邻元素,这样才能去掉重复元素。
    
    还有 list转set和set转到list都可以新建一个,在括号里面放入就行,如
   
List<Integer> list = new ArrayList<>(set);
---------------------------------------------
Set<String>set = new HashSet<String>(list);
 
版权声明:本文为duan18291953965原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
