I have some code to count permutations and combinations, and I\'m trying to make it work better for large numbers.
I\'ve found a better algorithm for permutations th
from scipy import misc
misc.comb(n, k)
should allow you to count combinations
from numpy import prod
def nCr(n,r):
numerator = range(n, max(n-r,r),-1)
denominator = range(1, min(n-r,r) +1,1)
return int(prod(numerator)/prod(denominator))
Using xrange() instead of range() will speed things up slightly due to the fact that no intermediate list is created, populated, iterated through, and then destroyed. Also, reduce() with operator.mul.
If your problem does not require knowing the exact number of permutations or combinations, then you could use Stirling's approximation for the factorial.
That would lead to code like this:
import math
def stirling(n):
# http://en.wikipedia.org/wiki/Stirling%27s_approximation
return math.sqrt(2*math.pi*n)*(n/math.e)**n
def npr(n,r):
return (stirling(n)/stirling(n-r) if n>20 else
math.factorial(n)/math.factorial(n-r))
def ncr(n,r):
return (stirling(n)/stirling(r)/stirling(n-r) if n>20 else
math.factorial(n)/math.factorial(r)/math.factorial(n-r))
print(npr(3,2))
# 6
print(npr(100,20))
# 1.30426670868e+39
print(ncr(3,2))
# 3
print(ncr(100,20))
# 5.38333246453e+20
There's a function for this in scipy which hasn't been mentioned yet: scipy.special.comb. It seems efficient based on some quick timing results for your doctest (~0.004 seconds for comb(100000, 1000, 1) == comb(100000, 99000, 1)).
[While this specific question seems to be about algorithms the question is there a math ncr function in python is marked as a duplicate of this...]
If you are computing N choose K (which is what I think you're doing with ncr), there is a dynamic programming solution that may be a lot faster. This will avoid factorial, plus you can keep the table if you want for later use.
Here is a teaching link for it:
http://www.csc.liv.ac.uk/~ped/teachadmin/algor/dyprog.html
I am unsure of how to better solve your first problem, though, sorry.
Edit: Here is the mock-up. There are some pretty hilarious off-by-one errors, so it can certainly stand some more clean up.
import sys
n = int(sys.argv[1])+2#100
k = int(sys.argv[2])+1#20
table = [[0]*(n+2)]*(n+2)
for i in range(1,n):
table[i][i] = 1
for i in range(1,n):
for j in range(1,n-i):
x = i+j
if j == 1: table[x][j] = 1
else: table[x][j] = table[x-1][j-1] + table[x-1][j]
print table[n][k]