Combinatoric 'N Choose R' In Java Math?


Answer :

The Formula

It's actually very easy to compute N choose K without even computing factorials.

We know that the formula for (N choose K) is:

    N!  --------  (N-K)!K! 

Therefore, the formula for (N choose K+1) is:

       N!                N!                   N!               N!      (N-K) ---------------- = --------------- = -------------------- = -------- x ----- (N-(K+1))!(K+1)!   (N-K-1)! (K+1)!   (N-K)!/(N-K) K!(K+1)   (N-K)!K!   (K+1) 

That is:

(N choose K+1) = (N choose K) * (N-K)/(K+1) 

We also know that (N choose 0) is:

 N! ---- = 1 N!0! 

So this gives us an easy starting point, and using the formula above, we can find (N choose K) for any K > 0 with K multiplications and K divisions.


Easy Pascal's Triangle

Putting the above together, we can easily generate Pascal's triangle as follows:

    for (int n = 0; n < 10; n++) {         int nCk = 1;         for (int k = 0; k <= n; k++) {             System.out.print(nCk + " ");             nCk = nCk * (n-k) / (k+1);         }         System.out.println();     } 

This prints:

1  1 1  1 2 1  1 3 3 1  1 4 6 4 1  1 5 10 10 5 1  1 6 15 20 15 6 1  1 7 21 35 35 21 7 1  1 8 28 56 70 56 28 8 1  1 9 36 84 126 126 84 36 9 1  

BigInteger version

Applying the formula for BigInteger is straightforward:

static BigInteger binomial(final int N, final int K) {     BigInteger ret = BigInteger.ONE;     for (int k = 0; k < K; k++) {         ret = ret.multiply(BigInteger.valueOf(N-k))                  .divide(BigInteger.valueOf(k+1));     }     return ret; }  //... System.out.println(binomial(133, 71)); // prints "555687036928510235891585199545206017600" 

According to Google, 133 choose 71 = 5.55687037 × 1038.


References

  • Wikipedia/Binomial coefficient
  • Wikipedia/Pascal's triangle
  • Wikipedia/Combination

The apache-commons "Math" supports this in org.apache.commons.math4.util.CombinatoricsUtils


The recursive definition gives you a pretty simple choose function which will work fine for small values. If you're planning on running this method a lot, or on large values, it would pay to memoize it, but otherwise works just fine.

public static long choose(long total, long choose){     if(total < choose)         return 0;     if(choose == 0 || choose == total)         return 1;     return choose(total-1,choose-1)+choose(total-1,choose); } 

Improving the runtime of this function is left as an exercise for the reader :)


Comments

Popular posts from this blog

Are Regular VACUUM ANALYZE Still Recommended Under 9.1?

Can Feynman Diagrams Be Used To Represent Any Perturbation Theory?