20210624力扣第47题:全排列2(java)

  • Post author:
  • Post category:java




题目

给定一个可包含重复数字的序列 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 版权协议,转载请附上原文出处链接和本声明。