0

A program that I'm writing needs a method that takes in three integers (say n, s, and k) and returns an boolean array with s true values, n-s false values, and with k (a variable between 0 and n choose k) determining their order. As an example, with the constant being n=5, s=2, and k=1, we could get the array

[true, true, false, false, false]

or with n=7, s=3, and k=2

[true, true, false, true, false, false, false]

It does not matter in particular what order k determines as long as its injective, i.e. different values of k resulting in different combinations.

One idea that I had was to use Integer.toBinaryString(int i) to turn each value of 'k' into a binary string and then turn the 1s and 0s into true and false, but unfortunately I don't see an easy way to let the number of 1s be determined by s. Does anyone know a good way or can show me the right direction?

2
  • You can simply use Mod of the k and like if it's an odd/even no, you toggle the states. Commented Jul 8, 2014 at 19:32
  • @ADi This has now been solved, but I am still curious to see if you can clarify? I don't see how modulus can be used in this example when you have a fixed number of 1s and 0s. Commented Jul 9, 2014 at 16:26

3 Answers 3

2

Here's the alternative I mentioned. It iterates over all n-bit numbers with only k bits set.

/**
 * Iterates all bit patterns containing the specified number of bits.
 *
 * See "Compute the lexicographically next bit permutation"
 * http://graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation
 *
 * @author OldCurmudgeon
 */
public class BitPattern implements Iterable<BigInteger> {

    // Useful stuff.

    private static final BigInteger ONE = BigInteger.ONE;
    private static final BigInteger TWO = ONE.add(ONE);
    // How many bits to work with.
    private final int bits;
    // Value to stop at. 2^max_bits.
    private final BigInteger stop;
    // Should we invert the output.
    private final boolean not;

    // All patterns of that many bits up to the specified number of bits - invberting if required.
    public BitPattern(int bits, int max, boolean not) {
        this.bits = bits;
        this.stop = TWO.pow(max);
        this.not = not;
    }

    // All patterns of that many bits up to the specified number of bits.
    public BitPattern(int bits, int max) {
        this(bits, max, false);
    }

    @Override
    public Iterator<BigInteger> iterator() {
        return new BitPatternIterator();
    }

    /*
     * From the link:
     *
     * Suppose we have a pattern of N bits set to 1 in an integer and
     * we want the next permutation of N 1 bits in a lexicographical sense.
     *
     * For example, if N is 3 and the bit pattern is 00010011, the next patterns would be
     * 00010101, 00010110, 00011001,
     * 00011010, 00011100, 00100011,
     * and so forth.
     *
     * The following is a fast way to compute the next permutation.
     */
    private class BitPatternIterator implements Iterator<BigInteger> {

        // Next to deliver - initially 2^n - 1

        BigInteger next = TWO.pow(bits).subtract(ONE);
        // The last one we delivered.
        BigInteger last;

        @Override
        public boolean hasNext() {
            if (next == null) {
            // Next one!
                // t gets v's least significant 0 bits set to 1
                // unsigned int t = v | (v - 1);
                BigInteger t = last.or(last.subtract(BigInteger.ONE));
                // Silly optimisation.
                BigInteger notT = t.not();
            // Next set to 1 the most significant bit to change,
                // set to 0 the least significant ones, and add the necessary 1 bits.
                // w = (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(v) + 1));
                // The __builtin_ctz(v) GNU C compiler intrinsic for x86 CPUs returns the number of trailing zeros.
                next = t.add(ONE).or(notT.and(notT.negate()).subtract(ONE).shiftRight(last.getLowestSetBit() + 1));
                if (next.compareTo(stop) >= 0) {
                    // Dont go there.
                    next = null;
                }
            }
            return next != null;
        }

        @Override
        public BigInteger next() {
            last = hasNext() ? next : null;
            next = null;
            return not ? last.not() : last;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException("Not supported.");
        }

        @Override
        public String toString() {
            return next != null ? next.toString(2) : last != null ? last.toString(2) : "";
        }

    }

    public static void main(String[] args) {
        // Generates 1, 10, 100. One bit set in a 3-bit number.
        int bits = 1;
        int max = 3;

        System.out.println("BitPattern(" + bits + ", " + max + ")");
        for (BigInteger i : new BitPattern(bits, max)) {
            System.out.println(i.toString(2));
        }
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

I can't run it this code now, but I accepted this answer since it looks good on inspection. I assume that if I wanted to get, for example, the sequences 001, 010, 100 (in some order), I would call BitPattern(3, 3, true) and Iterator()?
On an unrelated note: when I was learning Java, I was taught that methods shoulds start with a small letter and objects with a big letter. I see that you don't follow this, so is it a convention that should be avoided in your opinion as an experienced programmer? :)
@Sid - Added main to demonstrate how to get 1,010,100, you'll have to add the leading zeros yourself :) On an unrelated note ... - where do you see I have wandered from that? There are subtleties of that custom which state that constants should be uppercase and constructors are match their class name.
1

I think the keyword you are looking for is combinadic.

Here is what I finally came up with as a result of an answer to one of my questions in the Mathematics pages.

In essence you can pick the kth number in a sequence of n-bit numbers using this technique.

There's an excellent narrative on how it works in the accepted answer here.

If, however, you are just looking to iterate through k-bit numbers there are other more efficient ways.

Comments

-1

How about shuffling the array using k to seed the Randomness?

myArray = [true,true,true,false,false,...]
Collections.shuffle(myArray, new Random(k))

2 Comments

That would be ideal but I can't have the same shuffled array twice for different values of k below (n choose k). Does this method avoid that?
There is a chance that different values of k could provide the same output I believe.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.