Leetcode--Java--47. Permutations II

题目描述

Given a collection of numbers, nums, that might contain duplicates, return all possible unique permutations in any order.

样例描述

Example 1:

Input: nums = [1,1,2]
Output:
[[1,1,2],
 [1,2,1],
 [2,1,1]]
Example 2:

Input: nums = [1,2,3]
Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
 

Constraints:

1 <= nums.length <= 8
-10 <= nums[i] <= 10

思路

  1. 这题不能直接暴力dfs,因为可能存在重复元素,例如1,1',21',1,2,其实是同一种排列方式。(这里用1,1’ 人为区分两个相同元素)。所以需要进行剪枝。剪枝的前提是排序,必须先对原数组排序。
  2. 为了不出现上面的重复排列,规定1’都必须在1的后面出现,否则肯定有重复。即我们对1’开头的排列全部剪枝了。 具体体现到代码中就是,如果排序后的数组中存在俩个相同的数,由于我们是按序遍历,这俩数肯定是相邻,规定要是前面那个没有使用过的话,后面的就不应该出现,就直接continue
    保证相同的数字都相邻,然后每次填入的数一定是这个数所在重复数集合中「从左往右第一个未被填过的数字」
  3. 回溯时一定记得恢复递归前的状态。

代码

class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
       int len=nums.length;
       List<List<Integer>> ans=new ArrayList<>();
       //排序是剪枝的前提
       Arrays.sort(nums);
       Deque<Integer> path=new ArrayDeque<>(len);
       //状态数组,表示数字是否被使用过
       boolean[] used=new boolean[len];
       dfs(nums,len,0,ans,path,used);
       return ans;
    }
    
    void dfs(int[] nums,int len,int cur,List<List<Integer>> ans,Deque<Integer> path,boolean[] used){
         //如果当前cur等于长度,表明形成了一个排序,加入到结果集中
         if(cur==len){
             ans.add(new ArrayList<>(path));
             return;
         }
         //依次遍历每个数字
        for(int i=0;i<len;i++){
            //若该数没有被使用过
            if(!used[i]){
                //若有俩数相等,且前面那个没出现过,则后面的不能出现
                if(i>0&&nums[i]==nums[i-1]&&!used[i-1])
                 continue;
                used[i]=true;
                path.addLast(nums[i]);
                dfs(nums,len,cur+1,ans,path,used);
                //回溯法一定要记得恢复递归前的状态  (其实就是dfs前面的代码的对称写法)
                used[i]=false;
                path.removeLast();
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值