• 返回某集合的所有子集


    题目:

      给定一个int数组A和数组的大小n,编写一个方法返回集合A的所有子集。注意集合里面的元素互异。

      解这道题的思想本质上就是元素选与不选的问题。由此大概有三种方法解这道题。

      递归法:如果只有一个元素,那么它的子集有两个,分别是本身和空集,然后在已经有一个元素的子集的基础上,第二个元素有两种选法,那就是加入到前面的子集里面或者不加入到前面的子集里面,也就是选与不选的问题。而前面的子集一共有两个,对每一个子集都有来自于下一个元素的加入和不加入两种选法。那么就可以得出两个元素的子集一共有四个。依次类推,就可以得出n的元素所有子集(这里n个元素的子集一共有2n个,非空子集一共有2n-1个。)。

      迭代法:思想和递归法基本一样,区别是代码的方式不一样,关于它们的区别前面博客里面写着的。

      二进制法:观察规律可以发现任何元素只有两种情况可以选择,于是我们就可以想到用二进制来代表选与不选的情况。"1"代表这个元素已经选择,而"0"代表这个元素没有选择。假如三个元素 A B C ,那么 101 就代表B没有选择,所以101代表的子集为AC。

    代码:

      1 import java.util.ArrayList;
      2 import java.util.Arrays;
      3 import java.util.HashSet;
      4 import java.util.Set;
      5 
      6 public class 非空子集 {
      7 
      8     public static void main(String[] args) {
      9         int[] A = {1, 2, 3};
     10 
     11         ArrayList<ArrayList<Integer>> subsets = getSubsets(A, A.length);
     12         System.out.println(subsets);
     13         
     14         Set<Set<Integer>> subsets2 = getSubsets2(A, A.length);
     15         System.out.println(subsets2);
     16         
     17         Set<Set<Integer>> subsets3 = getSubsets3(A, A.length);
     18         System.out.println(subsets3);
     19 
     20 
     21     }
     22     
     23     /**
     24      * 二进制法,迭代法,或者逐步生成法,性能最高
     25      */
     26     public static ArrayList<ArrayList<Integer>> getSubsets(int []A,int n){
     27         Arrays.sort(A);  // 正序排序
     28         ArrayList<ArrayList<Integer>> res = new ArrayList<>();  //大集合
     29         for(int i = ex(2, n);i>0;i--){         //大数字-1
     30             ArrayList<Integer> s = new ArrayList<>();  //对每个i建立一个集合
     31             for(int j = n-1;j>=0;j--){    //检查哪个位上的二进制为1,从高位开始检查,高位对应着数组靠后的元素
     32                 if(((i>>j)&1)==1){
     33                     s.add(A[j]);
     34                 }
     35             }
     36             res.add(s);
     37         }
     38         // 生成的结果逆序排序,如果要生成正序排列,很难完成,只有数组反转实现。
     39         return res;
     40     }
     41     
     42     /**
     43      * 逐步生成迭代大法
     44      */
     45     public static Set<Set<Integer>> getSubsets2(int[]A,int n){
     46         Set<Set<Integer>> res = new HashSet<>();  //初始化为空集
     47         res.add(new HashSet<>());
     48         //从第一个元素开始处理
     49         for(int i=0;i<n;i++){
     50             Set<Set<Integer>> res_new = new HashSet<>(); //新建一个大集合
     51             res_new.addAll(res);  //把原来集合中的每个子集都加入到新集合中
     52             for(Set e:res){     //遍历之前的集合,全部克隆一遍
     53                 Set clone = (Set) ((HashSet) e).clone(); 
     54                 clone.add(A[i]);  //把当前元素加进去
     55                 res_new.add(clone); //把克隆的子集加到大集合中
     56             }
     57             res = res_new;
     58         }
     59         return res;
     60     }
     61     
     62     /**
     63      * 递归法  增量构造法
     64      */
     65     public static Set<Set<Integer>> getSubsets3(int[]A,int n){
     66         // Arrays.sort(A);
     67         return getSubsetsCore(A,n,n-1);
     68     }
     69     
     70     public static Set<Set<Integer>> getSubsetsCore(int[] A, int n, int cur) {
     71         Set<Set<Integer>> newSet = new HashSet<>();
     72         if (cur==0) {     //处理第一个元素
     73             Set<Integer> nil = new HashSet<>();        //空集
     74             Set<Integer> first = new HashSet<>();    //包含第一个元素的集合
     75             first.add(A[0]);
     76             newSet.add(nil);
     77             newSet.add(first);
     78             return newSet;
     79         }
     80         Set<Set<Integer>> oldSet = getSubsetsCore(A, n, cur-1);
     81         for(Set<Integer> set:oldSet){
     82             //对于每个子集,cur这个元素可以加进去,也可以不加进去
     83             newSet.add(set);  //保留原样 选择不加进去
     84             Set<Integer> clone = (Set<Integer>) ((HashSet) set).clone();
     85             clone.add(A[cur]);        //添加当前元素
     86             newSet.add(clone);
     87         }
     88         return newSet;
     89     }
     90 
     91     public static int ex(int a,int n){
     92         if(n==0)return 1;
     93         if(n==1)return a;
     94         int temp = a; // a的1次方
     95         int res = 1;
     96         int exponent = 1;
     97         while((exponent<<1)<n){
     98             temp = temp * temp;
     99             exponent = exponent << 1;
    100         }
    101         res *= ex(a,n-exponent);
    102         return res * temp;
    103     }
    104 
    105 }

    结果:

      

      

  • 相关阅读:
    从头梳理一下经常问到的 “零拷贝” 问题!
    Redis缓存使用中的热key问题
    使用Redis,你必须知道的21个注意要点
    一文理解 Redis 的核心原理与技术!
    大厂常问的Redis面试题
    三种不同场景下的 Kubernetes 服务调试方法
    Docker 和 Kubernetes:root 与特权
    DRBD详细解说及配置过程记录
    MySQL 高可用方案-PXC环境部署记录
    MySQL高可用方案
  • 原文地址:https://www.cnblogs.com/xiaoyh/p/10344523.html
Copyright © 2020-2023  润新知