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
If you don't need a pure-python solution, gmpy2 might help (gmpy2.comb
is very fast).
For N choose K you could use Pascals triangle. Basically you would need to keep array of size N around to compute all the N choose K values. Only additions would be required.
More efficient solution for nCr - space wise and precision wise.
The intermediary (res) is guaranteed to always be int and never larger than the result. Space complexity is O(1) (no lists, no zips, no stack), time complexity is O(r) - exactly r multiplications and r divisions.
def ncr(n, r):
r = min(r, n-r)
if r == 0: return 1
res = 1
for k in range(1,r+1):
res = res*(n-k+1)/k
return res
Two fairly simple suggestions:
To avoid overflow, do everything in log space. Use the fact that log(a * b) = log(a) + log(b), and log(a / b) = log(a) - log(b). This makes it easy to work with very large factorials: log(n! / m!) = log(n!) - log(m!), etc.
Use the gamma function instead of factorial. You can find one in scipy.stats.loggamma
. It's a much more efficient way to calculate log-factorials than direct summation. loggamma(n) == log(factorial(n - 1))
, and similarly, gamma(n) == factorial(n - 1)
.
You could input two integers and import math library to find the factorial and then apply the nCr formula
import math
n,r=[int(_)for _ in raw_input().split()]
f=math.factorial
print f(n)/f(r)/f(n-r)
For Python until 3.7:
def prod(
items,
start=1):
for item in items:
start *= item
return start
def perm(n, k):
if k > n or k < 0 or n < 0:
raise ValueError(
'Values must be non-negative and n >= k in perm(n, k)')
else:
return prod(range(n - k + 1, n + 1))
def comb(n, k):
if k > n or k < 0 or n < 0:
raise ValueError(
'Values must be non-negative and n >= k in comb(n, k)')
elif k > n - k:
# return perm(n, k) // math.factorial(n - k)
return math.factorial(n) // math.factorial(k) // math.factorial(n - k)
else:
# return perm(n, n - k) // math.factorial(k)
return math.factorial(n) // math.factorial(n - k) // math.factorial(k)
For Python 3.8+: