An algorithm for total permutation and non empty subsets -- permutation and combination

Posted by offsprg01 on Sat, 02 Nov 2019 17:48:42 +0100

In mathematics, permutation and combination are very important. In algorithm, we will introduce several methods to find all permutations and all subsets of elements.

I. full arrangement

Full Permutation, if implemented by recursion, is the problem of element exchange, while if implemented by iteration, it is the problem of adding the current character before or after the formed character. Here, we use iteration, common recursion and multiple recursion + backtracking respectively.

Iterative implementation

    //Iterative implementation, subproblem: add before, add after, add in the middle
    static List<String> getPermutation(String s)  {
        List<String> res = new ArrayList<>();
        res.add(s.charAt(0)+"");
        
        for(int i=1;i<s.length();i++) {
            List<String> res_new = new  ArrayList<>();
            char c = s.charAt(i);
            for(String e:res) {
                String str = c + e;
                res_new.add(str);//Add to the front
                str = e + c;
                res_new.add(str);//Add to the back
                for(int j=1;j<e.length();j++) {
                    str =  e.substring(0,j)+c+e.substring(j);
                    res_new.add(str);
                }
                res = res_new;
            }
        }
        System.out.println(res.size());
        return res;
    }

Recursive implementation

    /**
     * Recursive total permutation, subproblem
     * @param s
     * @param k Pointer to the character in the specified string child, generally 0
     * @return
     */
    static List<String> getPermutation1(String  s,int k) {
        List<String> res_new = new  ArrayList<>();
        if(k == 0) {
            char ch = s.charAt(0);
            res_new.add(ch+"");
            return res_new;
        }
        List<String> res_old =  getPermutation1(s,k-1);
        
        char c =  s.charAt(k);
        for(String e : res_old) {
            String str = c + e;
            res_new.add(str);
            str = e + c;
            res_new.add(str);
            
            for(int i=1;i<e.length();i++) {
                str =  e.substring(0,i)+c+e.substring(i);
                res_new.add(str);
            }
        }
        return res_new;
    }

Implementation of multiple recursion + backtracking

    /**
     * Multiple recursion + backtracking
     * @param A Character array
     * @param k Current element subscript
     */
    static void getPermutation2(char[] A, int k)  {
        if(k==A.length-1) {
            for (char c : A) {
                System.out.print(c);
            }
            System.out.println();
            return;
        }
        
        for(int i=k;i<A.length;i++) {
            swap(A,i,k);//Change every subsequent character to k
            getPermutation2(A,k+1);
            swap(A,i,k);//To flash back
        }
    }
    
    static void swap(char[] arr,int x,int y) {
        char tem = arr[x];
        arr[x] = arr[y];
        arr[y] = tem;
    }

2. Finding (non empty) subsets

Finding subsets is a problem for a collection to have or not to have this element. It can be implemented by iteration, recursion, or binary.

Note: there should be an empty set at the beginning. This empty set is the start state of the subset. If there is no empty set, that is, only one element set will be started. At this time, only one element will be added / not added, so there will be fewer other single elements.

Iterative implementation

    /**
     * Iterative implementation
     * @param arr
     */
    static Set<Set<Integer>> subset(int[] arr){
        Set<Set<Integer>> res = new HashSet<>();
        res.add(new HashSet<>());//Initializing a bitspace
        for(int i=0;i<arr.length;i++) {
            Set<Set<Integer>> newSet = new  HashSet<>();
            newSet.addAll(res);
            for(Set<Integer> set:res) {
                Set<Integer> clone =  (Set<Integer>)((HashSet)set).clone();
                clone.add(arr[i]);
                newSet.add(clone);
            }
            res = newSet;
        }
        return res;
    }

Recursive implementation

    /**
     * Recursive implementation
     * @param arr
     * @param cur arr Array maximum subscript
     * @return
     */
    static Set<Set<Integer>> subset(int[]  arr,int cur) {
        Set<Set<Integer>> newSet = new  HashSet<>();
        if(cur == 0) {//Exit one must be placed in the front of the method
            Set<Integer> nullSet = new  HashSet<>();
            Set<Integer> fir_element = new  HashSet<>();
            fir_element.add(arr[0]);
            newSet.add(nullSet);
            newSet.add(fir_element);
            return newSet;
        }
        Set<Set<Integer>> oldSet =  subset(arr,cur-1);
        for(Set<Integer> set : oldSet) {
            //Backup set
            Set<Integer> clone =  (Set<Integer>)((HashSet)set).clone();
            newSet.add(set);//Add collection without elements
            clone.add(arr[cur]);//Add elements to the backup set
            newSet.add(clone);//Add collection of elements
        }
        return newSet;
    }

Binary implementation

    /**
     * Binary implementation
     * @param A
     * @return
     */
    static Set<Set<Integer>> subset(int[] A){
        char[][] bin_arr = new  char[(int)Math.pow(2, A.length)][];
        for(int i=0;i<bin_arr.length;i++) {
            bin_arr[i] = new  StringBuilder(Integer.toString(i,2)).reverse().toString().toCharArray();
        }
        Set<Set<Integer>> res = new HashSet<>();
        for(int i=0;i<bin_arr.length;i++) {
            Set<Integer> tem = new HashSet<>();
            for(int j=0;j<bin_arr[i].length;j++)  {
                if(bin_arr[i][j] ==  '1')tem.add(A[j]);
            }
            res.add(tem);
            tem = null;//Reclaim the HashSet object pointed by tem;
        }
        return res;
    }