LeetCode#47. Permutations II

  • 题目:一个包含重复元素的数组,求该数组的全部唯一的组合
  • 难度:Medium
  • 思路:求元素的组合序列,必然用回溯法来求,但这里的问题是数组的元素包含重复元素,但是组合列表不能有重复,所以重点在于怎么添加限制条件来排除组合列表出现的重复组合。
  • 代码:

    我的代码很不友好,代码量太大

    我用来排除出现重复列表的方法是:
    1.在为组合添加第一个元素的时候,加上一个判断(if nums[i] == nums[i-1]  then i++)
    2.在回溯的方法里,用一个set来存储已经访问过的数组下标,然后,判断该下标元素是否被访问过了,访问过的元素不应该添加到这个组合中
    
    通过上面两步的过滤后,还会出现一个问题,组合中的后面元素是相同,那就出现组合元素相同的情况。例如,数组为1,1,2 那么只用上面两个过滤,则会出现结果为[[1,1,2],[1,2,1],[2,1,1],[2,1,1]] 
    
    于是再在回溯方法中加上一个判断条件
    3. if(nums[i] == nums[i-1] && nums[i-1] not in set) 这说明值相同的元素中的第一个如果不在组合中,那么这些相同的元素都不应该被访问添加到组合中,否则出现了重复(换句话说,相同的一串元素只有一种组合方式,跟顺序无关) 
    
public class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        if(nums == null || nums.length == 0) {
            return result;
        }
        Arrays.sort(nums);
        for(int i = 0; i < nums.length; i++) {
            while(i > 0 && i < nums.length && nums[i] == nums[i-1]){
                i++;
            }
            if(i < nums.length){
                List<Integer> tmp = new ArrayList<>();
                tmp.add(nums[i]);
                LinkedHashSet<Integer> set = new LinkedHashSet<>();
                set.add(i);
                backtrack(result, tmp, nums, set);
            }

        }
        return result;
    }
    public void backtrack(List<List<Integer>> list, List<Integer> tmp, int[] nums, LinkedHashSet<Integer> set) {
        if(tmp.size() == nums.length) {
            list.add(new ArrayList<>(tmp));
            return;
        }else {
            for(int i = 0; i < nums.length; i++) {
               if(set.contains(i)){
                   continue;
               }
               if( i > 0 && nums[i] == nums[i-1] && !set.contains(i-1)){
                   continue;
               }
               set.add(i);
                tmp.add(nums[i]);
                backtrack(list, tmp, nums, set);
                set.remove(i);
                tmp.remove(tmp.size()-1);
            }
        }
    }
}

通过分析,上述三个过滤条件,发现第1点和第3点其实做的是同一件事,不管对于组合中的第1个元素还是其他元素,数组中相同元素都只能有一个下标被添加到组合中,于是有了一下的改进代码
改进代码

public class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        if(nums == null || nums.length == 0) {
            return result;
        }
        Arrays.sort(nums);
        backtrack(result, new ArrayList<>(), nums, new LinkedHashSet<Integer>());
        return result;
    }
    public void backtrack(List<List<Integer>> list, List<Integer> tmp, int[] nums, LinkedHashSet<Integer> set) {
        if(tmp.size() == nums.length) {
            list.add(new ArrayList<>(tmp));
            return;
        }else {
            for(int i = 0; i < nums.length; i++) {
               if(set.contains(i)){
                   continue;
               }
               if( i > 0 && nums[i] == nums[i-1] && !set.contains(i-1)){
                   continue;
               }
               set.add(i);
                tmp.add(nums[i]);
                backtrack(list, tmp, nums, set);
                set.remove(i);
                tmp.remove(tmp.size()-1);
            }
        }
    }
}

数组中没有重复元素的排列组合
Permutions

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值