子集II

Subsets II

​ Given an integer array nums that may contain duplicates, return all possible subsets(the power set). The solution set must not contain duplicate subsets. Return the solution in an order.

在这里插入图片描述
​ 题目的输入是一个数组,其中可能含有重复的元素;要求的结果是这个数组的所有子集的集合,也就是幂集,且结果集合中不能含有重复的集合,但是不要求顺序。

​ 而且我注意到题目的约束条件,数组长度居然最多只有10,数组元素的绝对值最大值也只有10

​ 既然这样,那么使用暴力破解方法可能会成功

  • 解法一

    首先对输入数组进行排序,然后使用回溯法得出数组元素所有可能的组合,再利用Set集合对得到的结果进行去重处理,即可得到结果。

    代码如下:

    public class Solution {
        public List<List<Integer>> subsetsWithDup(int[] nums) {
            Arrays.sort(nums);
            Set<List<Integer>> result = new HashSet<>();
            List<Integer> cur = new ArrayList<>();
            flash(nums, 0, cur, result);
            return new ArrayList<>(result);
        }
    
        /*
        * @param nums 原输入数组
        * @param now 当前决策到数组中的哪一位置
        * @param current 当前方案
        * @param result 最终方案
         */
        public void flash(int[] nums, int now, List<Integer> current, Set<List<Integer>> result) {
            //所有位置都决策完毕,将当前方案放入最终结果集
            if(nums.length == now) {
                result.add(new ArrayList<>(current));
                return;
            }
    
            //选择当前位置的元素,往下决策
            current.add(nums[now]);
            flash(nums, now+1, current, result);
    
            //不选当前位置的元素(回溯),往下决策
            current.remove(current.size()-1);
            flash(nums, now+1, current, result);
        }
    }
    

    结果确实可以通过
    在这里插入图片描述

  • 解法二

    由于数组的长度只有10,我们可以用一个二进制数的后十位分别表示数组的10个元素有没有被选择。这样就避免了回溯。

    同样,最终得到的结果集也需要利用Set进行去重处理。

    具体实现的代码如下:

    public class Solution2 {
        public List<List<Integer>> subsetsWithDup(int[] nums) {
            Arrays.sort(nums);
            Set<List<Integer>> result = new HashSet<List<Integer>>();
            List<Integer> current = new ArrayList<>();
    
            //枚举所有的选择状态,例如[1, 2],它的所有状态就有[],[1],[2],[1,2],分别对应00、01、10、11这几种状态
            //可能的状态就有2^n种,这里用移位运算代替求幂,提高效率
            int n = nums.length;
            for(int i = 0; i < (1<<n); i++) {
                current.clear();
    
            //对当前状态进行逐位检查,如果当前状态为1代表被选择,加入当前方案中
                for(int j = 0; j < n; j++) {
                    int temp = (i >> j) & 1;
                    if(temp == 1)
                        current.add(nums[j]);
                }
    
                result.add(new ArrayList<>(current));
            }
    
            return new ArrayList<>(result);
        }
    }
    

    提交结果如下:
    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值