Ryan Fu
Ryan Fu

Reputation: 349

Combination algorithm Java

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

Answers (1)

Gilbert Le Blanc
Gilbert Le Blanc

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

Related Questions