1. 程式人生 > >陣列---求陣列組成的集合的所有子集

陣列---求陣列組成的集合的所有子集

題目

給定一個數組,求陣列的所有子集,要求每個子集中的元素是升序的;
如:[1,2,3]
則:
[]
[1]
[2]
[3]
[1,2]
[1,3]
[2,3]
[1,2,3]

解法1

遞迴,利用二叉樹思想;
第0層為空集;第i層表示將陣列第i個元素是否加入到集合中,左子樹表示加入,右子樹表示不加入;
最後,每個葉子表示一個子集;如下所示:
[]
[1] []
[1,2] [1] [2] []
[1,2,3] [1,2] [1,3] [1] [2,3] [2] [3] []

圖得出:只要原陣列有序,就可以保證每個子集有序

level=0 不加a[0],level+1 遞迴;加入a[0],level+1 遞迴;
level=1 不加a[1],level+1 遞迴;加入a[1],level+1 遞迴;
levle=2 不加a[2],level+1 遞迴;加入a[2],level+1 遞迴;
level=3 返回

每次遞迴中,需要上次的子集,在上次的子集中加入當前元素,所以在遞迴函式中,需要加入當前子集的引數;
level引數;

實現:

public static ArrayList<ArrayList<Integer>> subsets_1
(int[] S){ ArrayList<Integer> current=new ArrayList<Integer>(); ArrayList<ArrayList<Integer>> res=new ArrayList<ArrayList<Integer>>(); Arrays.sort(S); //排序 subsets_(S,current,0,res); return res; } private static void subsets_
(int[] s,ArrayList<Integer> current, int level, ArrayList<ArrayList<Integer>> res) { if(level==s.length){ res.add(new ArrayList<Integer>(current)); return; } subsets_(s,new ArrayList<Integer>(current),level+1,res); current.add(s[level]); subsets_(s,new ArrayList<Integer>(current),level+1,res); }

解法2

遞迴;
求[1,2,3]的全部子集,可以先求出[2,3]的全部子集,然後將在得出的全部子集中,每個加入1,後得到的全部子集+[2,3]的全部子集即為所求;
[2,3]的全部子集也是;

要保證每個子集有序,需要對遞迴中的每個子集加入結果時,排序

遞迴函式(a,start)陣列,從陣列的第幾個開始求子集;有返回值-子集的集合;
start=0 遞迴start++ 對返回的結果中的每個子集,加入結果中;每個子集加入a[0],加入結果中;
start=1 遞迴start++ 對返回的結果中的每個子集,加入結果中;每個子集加入a[1],加入結果中;
start=2 遞迴start++ 對返回的結果中的每個子集,加入結果中;每個子集加入a[2],加入結果中;
start=3 結果中加入空集,返回;

實現:

public static ArrayList<ArrayList<Integer>> subsets_2(int[] S){
        Arrays.sort(S);
        return subsets2_(S,0);
    }

    private static ArrayList<ArrayList<Integer>> subsets2_(int[] s, int k) {
        ArrayList<ArrayList<Integer>> res=new ArrayList<ArrayList<Integer>>();
        if(k==s.length){
            res.add(new ArrayList<Integer>());
            return res;
        }
        ArrayList<ArrayList<Integer>> tmp=subsets2_(s,k+1);
        int a=s[k];
        for(ArrayList<Integer> list:tmp){
            res.add(list);//加入原子集到結果中

            /*原子集中加入a後,再加入到結果中
             * 注意:不能直接在list中加a在加入到結果中,因為這樣加入後,res.add(list)中加入的list也會改變
             */
            ArrayList<Integer> t=new ArrayList<Integer>(list);
            t.add(a);
            Collections.sort(t);//注意排序
            res.add(t);
        }

        return res;
    }

解法3

位運演算法;
對於包含n個元素的陣列,用n位二進位制表示;子集中,每個元素存在表示1,不存在表示0;
子集一共全0-全1,所以一共有2^n個;

從0開始到2^n-1
當前的子集;
對每個數進行如下操作:
判斷該數的每一位,如果為1,則在當前的子集中加入該位在陣列中的對應元素;如果為0,則不加入;
對該數判斷完後,將當前的子集加入到結果集中;

實現:

public static ArrayList<ArrayList<Integer>> subsets_3(int[] S){
        ArrayList<ArrayList<Integer>> res=new ArrayList<ArrayList<Integer>>();

        Arrays.sort(S);

        int max=1<<S.length;//2^n;
        for(int i=0;i<max;i++){
            ArrayList<Integer> tmp=new ArrayList<Integer>();
            int num=i;

            int count=0;
            //判斷num的每一位
            while(num>0){
                if((num&1)==1){
                    tmp.add(S[count]);
                }
                count++;
                num=num>>1;
            }

            res.add(tmp);
        }

        return res;
    }