Find all subsets of length k in an array

前端 未结 13 1707
梦谈多话
梦谈多话 2020-11-27 05:34

Given a set {1,2,3,4,5...n} of n elements, we need to find all subsets of length k .

For example, if n = 4 and k = 2, the output would be

相关标签:
13条回答
  • 2020-11-27 05:41

    Here is an iterative version in python. Essence of it is increment_counters() function which returns all possible combinations. We know it needs to be called C(n,r) times.

    def nchooser(n,r):
        """Calculate the n choose r manual way"""
        import math
        f = math.factorial
        return f(n) / f(n-r) / f(r)
    
    def increment_counters(rc,r,n):
        """This is the essense of the algorithm. It generates all possible indexes.
        Ex: for n = 4, r = 2, rc will have values (0,1),(0,2),(0,3),(1,2),(1,3),(2,3).
        You may have better understanding if you print all possible 35 values for
        n = 7, r = 3."""
    
        rc[r-1] += 1     # first increment the least significant counter
        if rc[r-1] < n:  # if it does not overflow, return
            return
    
        # overflow at the last counter may cause some of previous counters to overflow
        # find where it stops (ex: in n=7,r=3 case, 1,2,3 will follow 0,5,6)
        for i in range(r-2,-1,-1): # from r-2 to 0 inclusive
            if rc[i] < i+n-r:
                break
        # we found that rc[i] will not overflow. So, increment it and reset the
        # counters right to it. 
        rc[i] += 1
        for j in range(i+1,r):
            rc[j] = rc[j-1] + 1
    
    def combinations(lst, r):
        """Return all different sub-lists of size r"""
        n = len(lst)
        rc = [ i for i in range(r) ]  # initialize counters
        res = []
        for i in range(nchooser(n,r)): # increment the counters max possible times 
            res.append(tuple(map(lambda k: lst[k],rc)))
            increment_counters(rc,r,n)
    
        return res
    
    0 讨论(0)
  • 2020-11-27 05:42

    Another intresting solution.

    #include<bits/stdc++.h>
    using namespace std;
    long factorial(int n) { return (n==1|| n==0|| n < 0) ? 1 : n *factorial(n-1) ;}
    void printS(int set[],int n,int k) 
    { 
    
       long noofsubset =  factorial(n) / (factorial(n-k)*factorial(k));
       bitset<32> z ((1 << (k)) - 1);
       string s = z.to_string();
        int i = 0;
            while(i<noofsubset)
            { 
                      for (int j = 0; j  < n;j++)
                      {
                          if(s[(32-n)+j] == '1')
                            cout << set[j]<<" ";
                      }
                        cout << endl;
                    next_permutation(s.begin(),s.end());
                    i++;
            } 
    }
    
    void printSubsetsOfArray(int input[], int size) {
        int k  = 3;
      printS(input,size,k)  ;
    }
    
    0 讨论(0)
  • 2020-11-27 05:47

    Check out my solution

    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.Set;
    
    
     public class Subset_K {
    public static void main(String[]args)
    {
        Set<String> x;
        int n=4;
        int k=2;
        int arr[]={1,2,3,4};
        StringBuilder sb=new StringBuilder();
        for(int i=1;i<=(n-k);i++)
            sb.append("0");
        for(int i=1;i<=k;i++)
            sb.append("1");
        String bin=sb.toString();
        x=generatePerm(bin);
        Set<ArrayList <Integer>> outer=new HashSet<ArrayList <Integer>>();
        for(String s:x){
            int dec=Integer.parseInt(s,2);
            ArrayList<Integer> inner=new ArrayList<Integer>();
            for(int j=0;j<n;j++){
                if((dec&(1<<j))>0)
                    inner.add(arr[j]);
            }
            outer.add(inner);
        }
        for(ArrayList<?> z:outer){
            System.out.println(z);
        }
    }
    
        public static Set<String> generatePerm(String input)
    {
        Set<String> set = new HashSet<String>();
        if (input == "")
            return set;
    
        Character a = input.charAt(0);
    
        if (input.length() > 1)
        {
            input = input.substring(1);
    
            Set<String> permSet = generatePerm(input);
    
            for (String x : permSet)
            {
                for (int i = 0; i <= x.length(); i++)
                {
                    set.add(x.substring(0, i) + a + x.substring(i));
                }
            }
        }
        else
        {
            set.add(a + "");
        }
        return set;
    }
    }
    

    I am working on a 4 element set for test purpose and using k=2. What I try to do is initially generate a binary string where k bits are set and n-k bits are not set. Now using this string I find all the possible permutations of this string. And then using these permutations I output the respective element in the set. Would be great if someone could tell me about the complexity of this problem.

    0 讨论(0)
  • 2020-11-27 05:48

    If you are looking for Iterator pattern answer then here you go.

    public static <T> Iterable<List<T>> getList(final Iterable<? extends T> list) {
    
        List<List<T>> listOfList = new ArrayList<>();
    
        for (T t: list)
            listOfList.add(Collections.singletonList(t));
    
        return listOfList;
    }
    public static <T> Iterable<List<T>> getIterable(final Iterable<? extends T> list, final int size) {
    
        final List<T> vals = new ArrayList<>();
        int numElements = 0;
        for (T t : list) {
            vals.add(t);
            numElements++;
        }
    
        if (size == 1) {
            return getList(vals);
        }
        if (size == numElements) {
            return Collections.singletonList(vals);
        }
    
        return new Iterable<List<T>>() {
    
            @Override
            public Iterator<List<T>> iterator() {
                return new Iterator<List<T>>() {
    
                    int currPos = 0;                    
                    Iterator<List<T>> nextIterator = getIterable(
                        vals.subList(this.currPos + 1, vals.size()), size - 1).iterator();
    
                    @Override
                    public boolean hasNext() {
                        if ((this.currPos < vals.size()-2) && (this.currPos+size < vals.size()))
                            return true;
                        return false;
                    }
    
                    @Override
                    public List<T> next() {
                        if (!nextIterator.hasNext()) {
                            this.currPos++;
                            nextIterator = getIterable(vals.subList(this.currPos+1, vals.size()), size-1).iterator();
                        }
                        final List<T> ret = new ArrayList<>(nextIterator.next());
                        ret.add(0, vals.get(this.currPos));
                        return ret;
                    }
                };
            }
        };
    }
    
    0 讨论(0)
  • 2020-11-27 05:49

    Slight improvement for @amit top voted answer:

    His code keep checking combinations even when there won't be any chance for them to reach the wanted length. We can stop creating combinations much earlier:

    e.g. for [1,2,3,4,5,6,7,8,9,10] , length = 8 , the code will still try all combinations of length 7,6,5,4,3,2,1 although they will obviously just be thrown away, halting only when idx reaches the end of the list.

    We can improve the running time by stopping earlier, when we already know the set we build + the optional remaining digits will still be too short.

    change :

    //unsuccessful stop clause
    if (idx == superSet.size()) return;
    
    

    into:

    // unsuccessful stop clause
    Integer maxFutureElements = superSet.size() - idx;
    if (current.size() + maxFutureElements < length) return;
    
    0 讨论(0)
  • 2020-11-27 05:50
       #include<iostream>
       #include<cstdio>
       #include<vector>
       using namespace std;
       vector<int> v;
       vector<vector<int> > result;
    
      void subset(int arr[],int k,int n,int idx){
      if(idx==n)
     return;
    
    if(k==1){
        for(int i=idx;i<n;i++)
         {
            v.push_back(arr[i]);
            result.push_back(v);
            v.pop_back();
         }
    }
    
     for(int j=idx;j<n;j++) {
      v.push_back(arr[j]);
      subset(arr,k-1,n,j+1);
      v.pop_back();
      }
     }
    
    int main(){
    int arr[] = {1,2,3,4,5,6,7};
    int k = 4;
    int n =sizeof(arr)/sizeof(arr[0]);
    subset(arr,k,n,0);
    
    for(int i = 0;i<result.size();i++)
     { 
      for(int j = 0;j<result[i].size();j++)
       {
         cout << result[i][j] << " ";
       }
       cout << endl;
     }
    }
    
    0 讨论(0)
提交回复
热议问题