问题
Let's say I have 2 groups of numbers:
{1, 2, 3},
{4, 5}
I'd like to create an algorithm (in Java) that outputs the following 6 combinations:
1,4
1,5
2,4
2,5
3,4
3,5
There can be an arbitrary number of groups and an arbitrary number of members within each group. So in the above example, there are 2 groups with the first group having 3 members and the second group having 2 members. Another example is the following (3 groups, 3 members in first groups and 2 members in second and third groups):
{1, 2, 3},
{4, 5},
{6, 7}
Which would yield the following 12 combinations:
1,4,6
1,4,7
1,5,6
1,5,7
2,4,6
2,4,7
2,5,6
2,5,7
3,4,6
3,4,7
3,5,6
3,5,7
How can I do this in Java? I'm trying to use recursion and I've looked at a similar question already but I'm still coming up short. Thanks for the help! (P.S. this is not for a homework assignment)
回答1:
Got a bit bored and decided to give it a shot. Should be exactly what you need:
public static void main(String args[]) {
ArrayList<int[]> input = new ArrayList<int[]>();
input.add(new int[] { 1, 2, 3 });
input.add(new int[] { 4, 5 });
input.add(new int[] { 6, 7 });
combine(input, new int[input.size()], 0);
}
private static void combine(ArrayList<int[]> input, int[] current, int k) {
if(k == input.size()) {
for(int i = 0; i < k; i++) {
System.out.print(current[i] + " ");
}
System.out.println();
} else {
for(int j = 0; j < input.get(k).length; j++) {
current[k] = input.get(k)[j];
combine(input, current, k + 1);
}
}
}
回答2:
If you can use libraries, Guava's Sets.cartesianProduct(List<Set<E>>) does exactly what you're looking for. (Disclosure: I contribute to Guava.)
回答3:
One possible approach (not necessarily the most efficient) might be to take a divide and conquer approach. It's relatively simple to find all the permutations of two groups (the dumbest way is just nested for loops). Let's say you write a function called permute
and it does permute(A,B)
where A (e.g. {(1), (2), (3)}) and B (e.g. {(4), (5)} are groups of numbers and it returns you all the permutations of A & B as a single group (e.g {(1,4), (1,5), (2,4), (2,5), (3,4), (3,5)}).
So when you have N groups instead of 2, the easiest thing to do is just pick off small portions of the problem. Let's say you have groups A, B and C. Rather than worrying about them all separately, you can think of it as something like:
permute(permute(A,B),C)
Find all the permutations of A and B first. Once you have that result, find all the permutations of that result with C. And four groups A, B, C, D might look like:
permute(permute(permute(A,B),C),D)
And so on. At each step along the way, you take the current permutation result and permute it with the next group in the list of groups that you got as input. You're only ever combining two groups at a time, so the algorithm doesn't have to change depending on the number of groups you get as input.
When you're doing recursion, there are a few major questions you need to answer:
Can you recursively break down the problem into smaller, more solvable problems? I think the examples above prove that you can.
What is the base case? What is the solution that will cause the recursion to stop and unwind? It should generally be something really simple that your recursion can work down towards. In this case, it probably comes down to something like
permute(A,{})
where {} is the empty set.What is the recursive case? How will you break off a chunk of the problem and recurse on a smaller subset of the problem? I think the initial explanation gives you one way of potentially doing this. Just break off one group at a time and permute it with your ever-growing result.
There are certainly other solutions to this problem, this is just the first that popped into my head. As N gets bigger and bigger, this algorithm will get prohibitively slow since it's not very efficient.
So even if you don't use this solution, I hope it gets you on the right track!
回答4:
How about the following pseudo code (w/o recursion)
// Create the initial result filled with the first set of numbers
List result = new List()
For each number in the first set
result.add(new List(number))
// Iterate over the following sets to permutate over
For each remaining set S
List newResult = new List()
For each list L in result
For each number N in S
newResult.add(copy of L with N added)
result = newResult
来源:https://stackoverflow.com/questions/10262215/how-to-create-cartesian-product-over-arbitrary-groups-of-numbers-in-java