65

Is there a built in method in a java library that can compute 'N choose R' for any N, R?

Michael Easter
  • 23,733
  • 7
  • 76
  • 107
Aly
  • 15,865
  • 47
  • 119
  • 191
  • 7
    What if the result overflows an int? Does that matter? Do you want the result as a BigInteger? – Mark Byers Feb 04 '10 at 16:06
  • 2
    I am just trying to calculate number of 2 card combinations with different deck sizes (up to 52) so shouldn't go over 1,326 (52 choose 2) – Aly Feb 04 '10 at 16:10
  • 13
    Well did you realise that 52! is `80658175170943878571660636856403766975289505440883277824000000000000`? Because judging by the answer you've accepted, you don't seem to have thought about the size of the numbers involved in that formula. By the way the answer for two cards is (n*(n-1))/2. You don't need a full implementation of 'n choose r' to get that. – Mark Byers Feb 04 '10 at 16:13
  • See http://stackoverflow.com/questions/1678690/what-is-a-good-way-to-implement-choose-notation-in-java for implementation considerations. – mob Feb 04 '10 at 16:18
  • Oh ok great thanks you are correct I had integer overflows – Aly Feb 04 '10 at 16:19
  • @MarkByers. A good implementation of (n, r) will never compute the full factorials! – Mad Physicist Oct 18 '17 at 18:52

17 Answers17

111

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

polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
51

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

Luigi Plinge
  • 50,650
  • 20
  • 113
  • 180
theomega
  • 31,591
  • 21
  • 89
  • 127
  • 7
    None of the previous links works. Lol! Those at Apache should took care of redirecting their old links to updated information. – Fran Marzoa Oct 05 '16 at 21:23
  • 1
    http://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math4/util/CombinatoricsUtils.html – arve0 Dec 10 '17 at 19:34
  • 1
    This link direct to calculating the stirlingS2 which is close but not Choose. The right method is binomialCoefficient(), see https://commons.apache.org/proper/commons-math/javadocs/api-3.3/org/apache/commons/math3/util/CombinatoricsUtils.html#binomialCoefficient(int,%20int) – Cohensius Mar 21 '22 at 10:15
24

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 :)

dimo414
  • 47,227
  • 18
  • 148
  • 244
  • I hate to nitpick, but I'm legitimately curious why I just got downvoted for this answer. Certainly polygenelubricants's answer is much more detailed, but I've used this function many times without issue, is there an error of some sort? – dimo414 Jul 27 '12 at 03:56
  • 3
    I didn't downvote you, but your algorithm will call chose 2*C(n,k)-1 times. I.e. in computing `choose(10,5)` it will make 503 recursive calls (2*C(10,5)-1 = 2*252-1 = 504-1). So it has no hope of computing C(40,20) which is about 138 billion. – ErikR Jan 26 '15 at 19:39
  • Agreed, the same is true of a basic Fibonacci implementation, or any number of algorithms that benefit from dynamic programming. Do you think my answer (specifically the suggestion to memoise the method) does not sufficiently cover that? – dimo414 Jan 27 '15 at 00:40
  • 3
    Perhaps if you had written the code with memoization included you wouldn't have gotten downvoted. As it stands it's not very usable. But some people thought your answer contributed something as you did get some up-votes. – ErikR Jan 27 '15 at 01:01
  • Yes, perhaps. Personally, dynamic programming is orthogonal to the actual issue, and different application needs will merit different caching schemes, but I'll grant someone could be disgruntled that this answer cannot be dropped in as-is. In any case, I'll try not to lose too much sleep over it :) – dimo414 Jan 27 '15 at 02:03
  • Vote up. The time complexity can be easily improved by a hashmap. – Tao Zhang Oct 29 '16 at 18:23
17

I am just trying to calculate number of 2 card combinations with different deck sizes...

No need to import an external library - from the definition of combination, with n cards that would be n*(n-1)/2

Bonus question: This same formula calculates the sum of the first n-1 integers - do you see why they're the same? :)

BlueRaja - Danny Pflughoeft
  • 84,206
  • 33
  • 197
  • 283
  • 2
    *(Answer to bonus question, one year later: There are `n-1` ways to pair the first card with another card, plus `n-2` ways to pair the second card with the remaining cards, etc.)* – BlueRaja - Danny Pflughoeft May 25 '11 at 22:21
5

binomialCoefficient, in Commons Math

Returns an exact representation of the Binomial Coefficient, "n choose k", the number of k-element subsets that can be selected from an n-element set.

Cohensius
  • 385
  • 7
  • 18
Valentin Rocher
  • 11,667
  • 45
  • 59
4

N!/((R!)(N-R)!)

There is a lot you can cancel down in this formula, so usually the factorials are no problem. Let's say that R > (N-R) then cancel down N!/R! to (R+1) * (R+2) * ... * N. But true, int is very limited (around 13!).

But then one could with each iteration also divide. In pseudocode:

d := 1
r := 1

m := max(R, N-R)+1
for (; m <= N; m++, d++ ) {
    r *= m
    r /= d
}

It is important to start the division with one, even though this seems to be superfluous. But let's make an example:

for N = 6, R = 2: 6!/(2!*4!) => 5*6/(1*2)

If we leave 1 out we would calculate 5/2*6. The division would leave the integer domain. Leaving 1 in we guarantee that we don't do that as either the first or second operand of the multiplication is even.

For the same reason we do not use r *= (m/d).

The whole thing could be revised to

r := max(R, N-R)+1
for (m := r+1,d := 2; m <= N; m++, d++ ) {
    r *= m
    r /= d
}
Ralph M. Rickenbach
  • 12,893
  • 5
  • 29
  • 49
2

The mathematical formula for this is:

N!/((R!)(N-R)!)

Shouldn't be hard to figure it out from there :)

Aistina
  • 12,435
  • 13
  • 69
  • 89
  • 26
    Yes it should. You don't want to compute enormous factorials if you're limited by the size of an `int`, for example. – Josh Lee Feb 04 '10 at 16:07
  • @jleedev: As if factoring against that would be that hard in the first place :P – Esko May 28 '10 at 12:10
  • You can do some factoring to clean it up a bit, but this definition still hits much larger numbers than you want to use. To get the best results, a choose algorithm should never compute a number larger than the result - those get big quickly enough as it is. – dimo414 May 20 '12 at 14:30
  • @dimo414. If you implement this as written, it will overflow every time, of course. If you remove all the factors from the larger of R! and (N-R)!, then use the fact that the result is always an integer, you do not need to worry about overflow in the intermediate results. – Mad Physicist Oct 18 '17 at 18:54
2

The following routine will compute the n-choose-k, using the recursive definition and memoization. The routine is extremely fast and accurate:

inline unsigned long long n_choose_k(const unsigned long long& n,
                                     const unsigned long long& k)
{
   if (n  < k) return 0;
   if (0 == n) return 0;
   if (0 == k) return 1;
   if (n == k) return 1;
   if (1 == k) return n;
   typedef unsigned long long value_type;
   value_type* table = new value_type[static_cast<std::size_t>(n * n)];
   std::fill_n(table,n * n,0);
   class n_choose_k_impl
   {
   public:

      n_choose_k_impl(value_type* table,const value_type& dimension)
      : table_(table),
        dimension_(dimension)
      {}

      inline value_type& lookup(const value_type& n, const value_type& k)
      {
         return table_[dimension_ * n + k];
      }

      inline value_type compute(const value_type& n, const value_type& k)
      {
         if ((0 == k) || (k == n))
            return 1;
         value_type v1 = lookup(n - 1,k - 1);
         if (0 == v1)
            v1 = lookup(n - 1,k - 1) = compute(n - 1,k - 1);
         value_type v2 = lookup(n - 1,k);
         if (0 == v2)
            v2 = lookup(n - 1,k) = compute(n - 1,k);
         return v1 + v2;
      }

      value_type* table_;
      value_type dimension_;
   };
   value_type result = n_choose_k_impl(table,n).compute(n,k);
   delete [] table;
   return result;
}
1

ArithmeticUtils.factorial is apparently deprecated now. Please try CombinatoricsUtils.binomialCoefficientDouble(n,r)

Gábor Bakos
  • 8,982
  • 52
  • 35
  • 52
0

Similar to the guava version, there is a BigIntegerMath class here by Richard J. Mathar refered to as org.nevec.rjm, which is the package of the classes.

Their implementation provides two signatures for the binomial method: int,int and BigInteger,BigInteger.

demongolem
  • 9,474
  • 36
  • 90
  • 105
0

Using a hashmap to improve @dimo414 's solution:

private static Map<Integer, Map<Integer, Integer>> map = new HashMap<>();
private static int choose(int total, int choose){
    if(total < choose)
        return 0;
    if(choose == 0 || choose == total)
        return 1;

    if (! (map.containsKey(total) && map.get(total).containsKey(choose))){
        map.put(total, new HashMap<>());
        map.get(total).put(choose, choose(total-1,choose-1)+choose(total-1,choose));
    }
    return map.get(total).get(choose);
}
Tao Zhang
  • 191
  • 2
  • 10
0
public static void combinationNcK(List<String> inputList, String prefix, int chooseCount, List<String> resultList) {
    if (chooseCount == 0)
        resultList.add(prefix);
    else {
        for (int i = 0; i < inputList.size(); i++)
            combinationNcK(inputList.subList(i + 1, inputList.size()), prefix + "," + inputList.get(i), chooseCount - 1, resultList);

        // Finally print once all combinations are done
        if(prefix.equalsIgnoreCase("")){
            resultList.stream().map(str->str.substring(1)).forEach(System.out::println);
        }
    }
}

public static void main(String[] args) {
    List<String> positions = Arrays.asList(new String[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12" });
    List<String> resultList = new ArrayList<String>();
    combinationNcK(positions, "", 3, resultList);
}
N00b Pr0grammer
  • 4,503
  • 5
  • 32
  • 46
0

As per the formula: n!/ ((n-k)! * k!) If we simply compute numerator and denominator, many computations will be wasted and probably the range of "int", "float" or even "BigInteger" can fill. Thus, to overcome this scenario, we can cancel out the things before even multiplying the values.

suppose n=6, k=3

which is => 6*5*4*3*2*1 / ((3*2) * (3*2))

suppose if we multiply the numerator, the range can fill. Better option is to cancel it out before even multiplying the values.

In this case--> if we cancel out everything we are just left with: (2*5*2)

multiplying these values are far easier and will require less computation.

======================================================

The below mentioned code will work "efficiently" for numbers where the:

  1. n == k
  2. k < n
  3. k == 0
  4. the difference between n and k is too huge, eg. n=1000, k=2
  5. k = n/2 (MOST TOUGHEST)
  6. Value of k is close to half of the value of n

Probably the code can be still improved.

BigInteger calculateCombination(int num, int k) {

    if (num == k || k == 0)
        return BigInteger.ONE ;

    int numMinusK = num - k;
    int stopAt; // if n=100, k=2 , can stop the multiplication process at 100*99
    int denominator;

    // if n=100, k=98 OR n=100, k=2 --> output remains same.
    // thus choosing the smaller number to multiply with
    if (numMinusK > k) {
        stopAt = numMinusK;
        denominator = k;
    } else {
        stopAt = k;
        denominator = numMinusK;
    }

    // adding all the denominator nums into list
    List<Integer> denoFactList = new ArrayList<Integer>();
    for (int i = 2; i <= denominator; i++) {
        denoFactList.add(i);
    }

    // creating multiples list, because 42 / 27 is not possible
    // but 42 / 3 and followed by 42 / 2 is also possible
    // leaving us only with "7"
    List<Integer> multiplesList = breakInMultiples(denoFactList);
    Collections.sort(multiplesList, Collections.reverseOrder());

    Iterator<Integer> itr;
    BigInteger total = BigInteger.ONE;
    while (num > 0 && num > stopAt) {

        long numToMultiplyWith = num;
        if (!multiplesList.isEmpty()) {
            itr = multiplesList.iterator();
            while (itr.hasNext()) {
                int val = itr.next();
                if (numToMultiplyWith % val == 0) {
                    numToMultiplyWith = numToMultiplyWith / val;
                    itr.remove();
                }
            }
        }

        total = total.multiply(BigInteger.valueOf(numToMultiplyWith));
        num--;
    }
    return total;

}

ArrayList<Integer> breakInMultiples(List<Integer> denoFactList) {
    ArrayList<Integer> multiplesList = new ArrayList<>();
    for (int i : denoFactList)
        updateListWithMultiplesOf(multiplesList, i);
    return multiplesList;
}

void updateListWithMultiplesOf(ArrayList<Integer> list, int i) {
    int count = 2;
    while (i > 1) {
        while (i % count == 0) {
            list.add(count);
            i = i / count;
        }
        count++;
    }
}
Ravi Soni
  • 953
  • 1
  • 7
  • 17
0

Already there are a lots of solutions submitted.

  1. Some solution didn't consider integer overflow.

  2. Some solution calculated all possible nCr while given n and r. Result is more time and space needed.

In most cases we need to calculate nCr directly. I am going to share one more solution.

static long gcd(long a, long b) {
    if (a == 0) return b;
    return gcd(b%a, a);
}

// Compute (a^n) % m
static long bigMod(long a, long n, long m) {
    if (n == 0) return 1;
    if (n == 1) return a % m;
    long ret = bigMod(a, n/2, m);
    ret = (ret * ret) % m;
    if (n % 2 == 1) return (ret * a) % m;
    return ret;
}

// Function to find (1/a mod m).
// This function can find mod inverse if m are prime
static long modInverseFarmetsTheorem(long a, long m) {
    if (gcd(a, m) != 1) return -1;

    return bigMod(a, m-2, m);
}

// This function finds ncr using modular multiplicative inverse
static long ncr(long n, long r, long m) {
    if (n == r) return 1;
    if (r == 1) return n;

    long start = n - Math.max(r, n - r) + 1;

    long ret = 1;
    for (long i = start; i <= n; i++) ret = (ret * i) % m;

    long until = Math.min(r, n - r), denom = 1;
    for (long i = 1; i <= until; i++) denom = (denom * i)  % m;

    ret = (ret * modInverseFarmetsTheorem(denom, m)) % m;

    return ret;
}
iamcrypticcoder
  • 2,609
  • 4
  • 27
  • 50
0

Instead of implementing n choose k recursively (which can get slow with large numbers), we can also make use of the fact that:

                n(n-1)(n-2)...(n-k+1)
  n choose k =  --------------------
                        k!

We still need to calculate k!, but this can be done much faster than the recursive method.

private static long choose(long n, long k) {
    long numerator = 1;
    long denominator = 1;

    for (long i = n; i >= (n - k + 1); i--) {
        numerator *= i;
    }

    for (long i = k; i >= 1; i--) {
        denominator *= i;
    }

    return (numerator / denominator);
}

Be aware that the choose method above assumes that neither n nor k is negative. Also, the long data type can overflow for large enough values. A BigInteger version should be used if the result resp. numerator and/or denominator are expected to exceed 64 bits.

Joshua Gloor
  • 13
  • 1
  • 4
-1
public static long nCr(int n, int r) {
    long a = n;
    long b = r;
    long c = (n - r);

    for (int o = (int)a - 1; o > 0; o--) { a = a * o; }
    for (int o = (int)b - 1; o > 0; o--) { b = b * o; }
    for (int o = (int)c - 1; o > 0; o--) { c = c * o; }

    return (a / (b * c)); // n! / r! * (n - r)!
}

Edited from answer I made few years back, where a, b, and c were ints and integer overflow made the method critically unusable. This one is not really any better in terms of reliability, but it's lazy.

This will brick as well, if the value goes over long's limit... Not very feasible unless you're trying to find some quick solution for a school project or something.

  • Its o-- everywhere. Also, this does not take care of integer overflows. – Jaydev Aug 06 '17 at 05:29
  • 1
    Very lazily fixed it; will take a read at the other answers written. The c-- flew past my head, and I was too accustomed to not even thinking about integer overflows (since I didn't really make anything else back then that had that as a problem). Thanks for telling me. – SusuKacangSoya Aug 06 '17 at 07:25
  • I am sorry to say, this implementation doesn't consider integer overflow which is the main problem while calculating nCr. – iamcrypticcoder Nov 12 '18 at 01:55