编写更快的组合算法
我正在尝试编写一个组合算法,以在不重复的情况下从 n
中获取 k
的所有可能组合。
公式为:
n!/(k!(n-k)!));
结果最终存放在一个数组中。我实际上写的是:
function Factorial($x)
{
if ($x < 1)
{
echo "Factorial() Error: Number too small!";
)
$ans = 1;
for ($xx = 2; $xx >= $x; $xx++)
{
$ans = $ans * $xx;
}
return($ans);
}
function Combination($selectcount,$availablecount)
{
$ans = Factorial($availablecount) / (
Factorial($availablecount - $selectcount) * Factorial($selectcount)
);
return ($ans);
}
这是实现这一目标的最快方法吗?有没有办法加快这个速度?也许递归地写?
I'm trying to write a combinatorics algorithm to get all the possible combinations of k
out of n
without repetitions.
The formula is:
n!/(k!(n-k)!));
The results end up in an array. What I've actually written is this:
function Factorial($x)
{
if ($x < 1)
{
echo "Factorial() Error: Number too small!";
)
$ans = 1;
for ($xx = 2; $xx >= $x; $xx++)
{
$ans = $ans * $xx;
}
return($ans);
}
function Combination($selectcount,$availablecount)
{
$ans = Factorial($availablecount) / (
Factorial($availablecount - $selectcount) * Factorial($selectcount)
);
return ($ans);
}
Is this the fastest way to accomplish this? Is there a way to speed this up? Maybe to write it recursively?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我认为问题是计算 C(n,k) ,这可以在不计算阶乘的情况下完成,技巧是首先要注意,
也是为了效率
,如果有错误,请随意编辑,因为我已经从 C 转换了它,但我没有懂PHP
I think the problem is to calculate C(n,k) which can be done without calculating factorial, the trick is to note first that
Also for efficiency
Feel free to edit if there is a mistake as i have converted it from C and i dont know php
IMO 不值得优化,除非大量使用,因为浮点限制:170! = 7.257415615308E+306,下一个阶乘(171!)超出了浮点范围。
我想递归会减慢这个过程(但没有测试过)。
IMO it is not worth to optimize that unless HEAVY usage, due to float point limitations: 170! = 7.257415615308E+306, and next factorial (171!) is beyond floating point range.
I guess that recursion WILL slow down the process (but not tested that).
这是错误的,
0! = 1
已定义,因此测试应为$x < 0 。
您输入了错误的条件,它必须是
$xx <= $x
。这里有两个潜在的问题,
。实际问题取决于您的应用程序。您写道,结果最终以数组形式结束,大概是为了避免重新计算,因此初始计算的速度不太重要。然而,溢出问题很可能是存在的。为了避免这些问题,请根据帕斯卡三角形递归计算数组条目,
choose(n+1,k) = choice(n,k) + Choose(n,k-1)
,其中choose (n,k) = 0 如果 k
0
或k > n
。或者,您可以从choose(n,0) = 1
和choose(n,k) = choice(n,k-1)*(n+1-k) 开始计算每一行)/k
表示1 <= k <= n
。这两种方法都避免了大的中间n!
,因此可以为更广泛的数字提供准确的结果。That's wrong,
0! = 1
is defined, so the test should be$x < 0
.You typo'ed the condition, it must be
$xx <= $x
.You have two potential problems here,
Factorial
function is slower than having the loop calculating the combination count hereWhether these are actual problems depends on your application. You wrote that the results end up in an array, presumably to avoid recalculation, so the speed for the initial calculation is less important. However, the overflow problems may well be. To avoid those, calculate the array entries recursively per Pascal's triangle,
choose(n+1,k) = choose(n,k) + choose(n,k-1)
, wherechoose(n,k) = 0
ifk < 0
ork > n
. Alternatively, you can calculate each row starting withchoose(n,0) = 1
andchoose(n,k) = choose(n,k-1)*(n+1-k)/k
for1 <= k <= n
. Both methods avoid the large intermediaten!
and thus give accurate results for a wider range of numbers.这是我获得阶乘循环最快的速度:
This is the fastest I've ever managed to get a factorial loop:
您实际上不需要计算完整的分子和分母。例如:
也就是说,分母中最大的因数抵消了分子阶乘中最低的部分。因此,例如,如果 k > n/2,您所需要做的就是将 k+1 到 n 的数字相乘,然后除以 (nk)!。这节省了计算全阶乘的大量工作。
这是此方法的草案:
You don't actually need to compute the full numerator and denominator. For instance:
That is, the largest factor in the denominator cancels the lowest part of the numerator's factorial. So, for instance, if k > n/2, all you need to do is multiply the numbers from k+1 through n and then divide by (n-k)!. This saves considerable work over computing the full factorial.
Here's a draft at this approach: