蓝桥杯|冲刺|基本数学问题|子集的三种解法

子集

假设**非空集合A中含有n个元素,则有:

  • A的子集个数为2^n。
  • A的真子集的个数为2^n - 1。
  • A的非空子集的个数为2^n - 1
  • A的非空真子集的个数为2^n - 2。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OIHj5SaG-1649345046631)(JAVA算法竞赛练习电子笔录.assets/image-20220407225614589-16493433758071.png)]

递归

//递归
public Set<Set<Integer>> getSubsetsRecurse(int []set ,int length,int cur){

    Set<Set<Integer>> finallySet = new HashSet<>();//最终那个大集合
    //递归出口
    if(cur == 0){
        //空集
        Set<Integer> nil = new HashSet<>();
        //一个元素
        Set<Integer> first = new HashSet<>();
        first.add(set[0]);
        finallySet.add(nil);
        finallySet.add(first);
        return finallySet;
    }
    //递归得到前n-1个元素的子集
    Set<Set<Integer>> oldSet = getSubsetsRecurse(set,length,cur-1);
    finallySet.addAll(oldSet);
    for (Set<Integer> oldSetElement:oldSet){
        //防止浅拷贝
        Set<Integer> clone = (Set<Integer>) ((HashSet) oldSetElement).clone();
        clone.add(set[cur]);
        finallySet.add(clone);
    }

    return finallySet;
}

迭代

注意迭代器修改集合问题

//
public Set<Set<Integer>> getSubsets(int []set ,int length,int cur){
    Set<Set<Integer>> finallySet = new HashSet<>();
    finallySet.add(new HashSet<>());
    for (int i = 0; i < length; i++) {
        //
        Set<Set<Integer>> tempSet = new HashSet<>();
        tempSet.addAll(finallySet);
        for (Set<Integer> s : finallySet) {
            //deep copy
            Set<Integer> clone = (Set<Integer>) ((HashSet) s).clone();
            clone.add(set[i]);
            tempSet.add(clone);
        }
        //finallySet.addAll(tempSet);
        finallySet = tempSet;//fast
    }
    return finallySet;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZMIziJrB-1649345046637)(JAVA算法竞赛练习电子笔录.assets/image-20220407231811908-16493446933312.png)]

二进制解法

此种方法可以按字典序输出

//binary利用二进制
public Set<Set<Integer>> getSubsets(Integer []set ,int length) {
    Arrays.sort(set,new Comparator<Integer>(){
        @Override
        public int compare(Integer o1, Integer o2) {
            return (o2-o1);//从大到小 快排 如果是o1-o2从小到大
        }
    });
    Set<Set<Integer>> finallySet = new HashSet<>();//非空子集
    for (int i = ((1<<length)-1);i>0;--i){
        Set<Integer> subSet = new HashSet<>();//每一个二进制数对应一个集合
        for(int j = length - 1;j >= 0; --j ){
            if(((i>>j)&1) == 1){
                subSet.add(set[j]);
            }
        }
        finallySet.add(subSet);
    }
    return finallySet;
}

测试

[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
[[1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值