Reputation: 349
I'm trying to write a function: private static ArrayList<boolean[]> Combo(int i, int j)
where it'd be a sort of "concrete" implementation of iCj
in math:
Combo(4,2)
would return an arraylist of {true, true, false, false}, {true, false, true, false}, {false, true, true, false}, {false, true, false, true}, {false, false, true, true}
(in no particular order).
Currently, I've got a recursive algorithm like this:
private static ArrayList<boolean[]> Combo(int i, int j) {
ArrayList<boolean[]> k = new ArrayList<boolean[]>();
if (i == 1 && j == 0) {
k.add(new boolean[]{false});
} else if (i == 1 && j ==1) {
k.add(new boolean[]{true});
} else if (j>i) {
;
} else {
ArrayList<boolean[]> a1 = Combo((byte) i/2,1);
ArrayList<boolean[]> a2 = Combo((byte) i/2,2);
ArrayList<boolean[]> a3 = Combo((byte) i/2,3);
ArrayList<boolean[]> a4 = Combo((byte) i/2,4);
ArrayList<boolean[]> a5 = Combo((byte) i/2,5);
ArrayList<boolean[]> a6 = Combo((byte) i/2,6);
ArrayList<boolean[]> a7 = Combo((byte) i/2,7);
ArrayList<boolean[]> a8 = Combo((byte) i/2,8);
ArrayList<boolean[]> a9 = Combo((byte) i/2,9);
k.addAll(merge(a1,a9,j));
k.addAll(merge(a2,a8,j));
k.addAll(merge(a3,a7,j));
k.addAll(merge(a4,a6,j));
k.addAll(merge(a5,a5,j));
}
return k;
}
private static ArrayList<boolean[]> merge(ArrayList<boolean[]> a1, ArrayList<boolean[]> a2, int tot) {
ArrayList<boolean[]> k = new ArrayList<boolean[]>();
for (boolean[] b : a1) {
for (boolean[] b1: a2) {
boolean[] c = new boolean[tot];
for (int i = 0 ; i< b.length; i++) {
c[i] = b[i];
}
for (int i = b.length; i<b.length+b1.length; i++) {
c[i] = b1[i-b.length];
}
k.add(b);
}
}
return k;
}
But I'm getting Exception in thread "main" java.lang.StackOverflowError
on line 129.
Can anyone please help me optimize this?
Upvotes: 0
Views: 98
Reputation: 51565
Jave method names should always start with a lower case letter.
You should also use a java.util.List
as a method return value.
I don't like writing recursive code, so I wrote an iterative solution. I used a bit trick I learned a while back to generate all combinations. The bit patterns of all the integers from zero to 2^N give all the combinations of N length.
In this code, I test for the number of true values you're seeking.
Here are my test results for 4,2 and 6,2. I formatted the results to fit in the answer.
[[true, true, false, false], [true, false, true, false],
[false, true, true, false], [true, false, false, true],
[false, true, false, true], [false, false, true, true]]
[[true, true, false, false, false, false],
[true, false, true, false, false, false],
[false, true, true, false, false, false],
[true, false, false, true, false, false],
[false, true, false, true, false, false],
[false, false, true, true, false, false],
[true, false, false, false, true, false],
[false, true, false, false, true, false],
[false, false, true, false, true, false],
[false, false, false, true, true, false],
[true, false, false, false, false, true],
[false, true, false, false, false, true],
[false, false, true, false, false, true],
[false, false, false, true, false, true],
[false, false, false, false, true, true]]
Here's the complete runnable code.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class CombinationAlgorithm {
public static void main(String[] args) {
CombinationAlgorithm ca = new CombinationAlgorithm();
List<boolean[]> comboList = ca.combo(4, 2);
ca.printList(comboList);
comboList = ca.combo(6, 2);
ca.printList(comboList);
}
public List<boolean[]> combo(int elementCount, int trueCount) {
List<boolean[]> comboList = new ArrayList<>();
if (elementCount < trueCount) {
// Return empty list
return comboList;
}
int limit = (int) Math.pow(2.0, elementCount);
for (int index = 0; index < limit; index++) {
if (Integer.bitCount(index) == trueCount) {
boolean[] values = new boolean[elementCount];
for (int bit = 0; bit < elementCount; bit++) {
if (getBit(index, bit) == 0) {
values[bit] = false;
} else {
values[bit] = true;
}
}
comboList.add(values);
}
}
return comboList;
}
private int getBit(int value, int bit) {
return (value >> bit) & 1;
}
private void printList(List<boolean[]> comboList) {
System.out.print("[");
for (int index = 0; index < comboList.size(); index++) {
boolean[] values = comboList.get(index);
System.out.print(Arrays.toString(values));
if (index < (comboList.size() - 1)) {
System.out.print(", ");
}
}
System.out.println("]");
}
}
Upvotes: 1