我写了两个函数来计算组合。第一个使用for循环,另一个使用递归阶乘函数。为什么第一个比第二个快?
def combinations(n: int, k: int) -> int:
# Collection >= Selection
if n < k:
raise ValueError(
"The size of the collection we are selecting items from must be "
"larger than the size of the selection."
)
# Sizes > 0
if n < 0 or k < 0:
raise ValueError(
"Cannot work with negative integers."
)
# Compute with standard python only
numerator = 1
for i in range(n + 1 - k, n+1):
numerator *= i
denominator = 1
for i in range(1, k+1):
denominator *= i
return int(numerator / denominator)
第二个函数需要定义为的阶乘函数:
def factorial(n: int) -> int:
if n < 0:
raise ValueError(
"Cannot calculate factorial of a negative number."
)
# Recursive function up to n = 0
return n * factorial(n - 1) if n - 1 >= 0 else 1
它的定义是:
def combinations2(n: int, k: int) -> int:
# Collection >= Selection
if n < k:
raise ValueError(
"The size of the collection we are selecting items from must be "
"larger than the size of the selection."
)
return int(factorial(n) / (factorial(k) * factorial(n - k)))
当我在IPython控制台上运行以下测试时,很明显哪个测试速度更快
%timeit combinations(1000, 50)
16.2 µs ± 1.95 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
和
%timeit combinations2(1000, 50)
1.6 ms ± 129 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
新版本的组合2
好的,在评论之后,我同意combinations2正在执行更多操作。所以我重写了阶乘和组合函数,这是它们的版本:
def factorial(n: int, lower: int=-1) -> int:
# n > 0
if n < 0:
raise ValueError(
"Cannot calculate factorial of a negative number."
)
# Recursive function up to n = 0 or up to lower bound
if n - 1 >= 0 and n - 1 >= lower:
return n * factorial(n - 1, lower)
return 1
现在可以有一个下限。注意,一般阶乘(a,b)=阶乘(a)/阶乘(b)。另外,这是Combines2函数的新版本:
def combinations2(n: int, k: int) -> int:
if n < k:
raise ValueError(
"The size of the collection we are selecting items from must be "
"larger than the size of the selection."
)
return int(factorial(n, n - k) / factorial(k))
但这又是他们的比较:
%timeit combinations(100, 50)
10.5 µs ± 1.67 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit combinations2(100, 50)
56.1 µs ± 5.79 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
答案 0 :(得分:4)
只需计算操作次数:
在combinations
中,您要对分子进行(n+1) - (n+1-k)
乘法,对分母进行(k+1) - 1
乘法。
总计:2k
个乘法
在cominations2
中,您要进行n + k + (n-k)
乘法,即2n
乘法。
您也正在进行2n
函数调用以进行递归。
有了k=50
和n=1000
,难怪第一个解决方案会更快。