简体   繁体   中英

Find all possible combinations of of a particular size for a set of numbers

I'm looking to solve the following problem :

Given two integers n and k, return all possible combinations of k numbers out of 1 2 3 ... n.

Make sure the combinations are sorted.

To elaborate,

  1. Within every entry, elements should be sorted. [1, 4] is a valid entry while [4, 1] is not.
  2. Entries should be sorted within themselves.

Example : If n = 4 and k = 2, a solution is:

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

This is the solution I have come up with :

public ArrayList<ArrayList<Integer>> combine(int n, int k) {

    //variable where the resultant sets of of numbers are to be stored
    ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();

    //finding all the subsets from 1-n of size k and storing them in result
    subset(n,result,k);

    //sorting the resultant set of subsets lexicographically
    Collections.sort(result,new Comparator<ArrayList<Integer>>(){

        @Override
        public int compare(ArrayList<Integer> a,ArrayList<Integer> b){

            int aSize = a.size();
            int bSize = b.size();

            for(int i=0;i<(int)Math.min(aSize,bSize);i++){

                int comparison = Integer.compare(a.get(i),b.get(i));
                if(comparison!=0) return comparison;
            }
               return Integer.compare(aSize,bSize);
        }
    });

    return result;
}


void subset(int n,ArrayList<ArrayList<Integer>> result,int size){
    for(int i=0;i<(1<<n);++i){

        //the arraylist to be added to the result
        ArrayList<Integer> element = new ArrayList<Integer>();

        //iterating 2^n times since those are the total number of possible subsets
        for(int j=0;j<n;++j)
            if((i&(1<<j))>0)
                element.add(j+1);


        //only adding the resultant subset to the result if it matches the size criteria
        if(element.size() == size)
            result.add(element);
    }
}

I'm looking at this answer and I can't help but think there must be a more optimal way of doing this.

By the looks of it, this program has a time complexity of O(nlogn * 2^n). Which is quite bad. I'm trying to calculate each and every subset before checking if they match the size criteria. Any way to find the number of subset by iterating only nCk times ?

nCk is the number of combinations we can hope to find. Where nCk = n!/(k!*(nk)!)

You can generate them directly in the right order (pseudocode):

for(i1 =  0 + 1; i1 <= n-k+1; ++i1)
for(i2 = i1 + 1; i2 <= n-k+2; ++i2)
for(i3 = i2 + 1; i3 <= n-k+3; ++i3)
for(i4 = i3 + 1; i4 <= n-k+4; ++i4)
....
for(ik = i? + 1; ik <= n-k+k; ++ik){
    output = [i1, i2, i3, ..., ik];
}

As You do not create the code on the fly, You can implement that via recursion like this:

private static void Iterate(int[] outp, int n, int k, int actIndex, int lastVal)
{
    if (actIndex > k)
    {
        System.out.println(Arrays.toString(outp));
        return;
    }

    for (int i = lastVal + 1; i <= n - k + actIndex; ++i)
    {
        outp[actIndex - 1] = i;
        Iterate(outp, n, k, actIndex + 1, i);
    }
}

and call it:

int n = 4;
int k = 2;
Iterate(new int[k], n, k, 1, 0);

output:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM