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,
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.