组合 'N 选择 R'在java数学中?
java库中是否有内置方法可以为任何N,R计算“N选择R”?
Is there a built in method in a java library that can compute 'N choose R' for any N, R?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
公式
实际上,计算
N 选择 K
非常容易,甚至无需计算阶乘。我们知道,
(N 选择 K)
的公式为:因此,
(N 选择 K+1)
的公式为:即:
我们还知道
( N 选择 K)
>(N select 0) 是:所以这给了我们一个简单的起点,使用上面的公式,我们可以找到任何
K > 的
与(N select K)
。 0K
乘法和K
除法。简单的帕斯卡三角形
将以上内容放在一起,我们可以轻松生成帕斯卡三角形,如下所示:
打印:
BigInteger
版本应用
BigInteger
的公式很简单:根据 Google,133 选择 71 = 5.55687037 × 1038。
参考文献
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:Therefore, the formula for
(N choose K+1)
is:That is:
We also know that
(N choose 0)
is:So this gives us an easy starting point, and using the formula above, we can find
(N choose K)
for anyK > 0
withK
multiplications andK
divisions.Easy Pascal's Triangle
Putting the above together, we can easily generate Pascal's triangle as follows:
This prints:
BigInteger
versionApplying the formula for
BigInteger
is straightforward:According to Google, 133 choose 71 = 5.55687037 × 1038.
References
apache-commons“数学”支持这一点
org.apache.commons.math4.util.CombinatoricsUtils
The apache-commons "Math" supports this in
org.apache.commons.math4.util.CombinatoricsUtils
递归定义为您提供了一个非常简单的选择函数,该函数对于较小的值可以很好地工作。如果您打算经常运行此方法,或者运行较大的值,则需要记住它,但除此之外也可以正常工作。
改进此函数的运行时间作为留给读者的练习:)
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.
Improving the runtime of this function is left as an exercise for the reader :)
无需导入外部库 - 根据组合的定义,
n
卡将是n* (n-1)/2
额外问题:这个相同的公式计算前
n-1
整数的总和 - 你明白为什么它们是相同的? :)No need to import an external library - from the definition of combination, with
n
cards that would ben*(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? :)二项式系数
,位于 Commons Math< /a>binomialCoefficient
, in Commons Math这个公式中有很多东西可以取消,所以阶乘通常没有问题。假设 R > (NR) 然后取消 N!/R!到 (R+1) * (R+2) * ... * N。但确实, int 非常有限(大约 13!)。
但每次迭代也可能会分裂。在伪代码中:
以 1 开始除法很重要,尽管这似乎是多余的。但让我们举个例子:
如果我们省略 1,我们将计算 5/2*6。除法将离开整数域。保留 1 可以保证我们不会这样做,因为乘法的第一个或第二个操作数是偶数。
出于同样的原因,我们不使用
r *= (m/d)
。整个事情可以修改为
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:
It is important to start the division with one, even though this seems to be superfluous. But let's make an example:
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
其数学公式是:
从那里应该不难算出来:)
The mathematical formula for this is:
Shouldn't be hard to figure it out from there :)
以下例程将使用递归定义和记忆来计算 n-choose-k。该例程极其快速且准确:
The following routine will compute the n-choose-k, using the recursive definition and memoization. The routine is extremely fast and accurate:
guava 具有 IntMath#binomial(int, int) ,LongMath#binomial(int, int) 和 BigIntegerMath#binomial(int, int)。
guava has IntMath#binomial(int, int), LongMath#binomial(int, int) and BigIntegerMath#binomial(int, int).
ArithmeticUtils.factorial 现在显然已被弃用。请尝试
CombinatoricsUtils.binomialCoefficientDouble(n,r)
ArithmeticUtils.factorial
is apparently deprecated now. Please tryCombinatoricsUtils.binomialCoefficientDouble(n,r)
与番石榴版本类似,有一个 BigIntegerMath 类 此处,由 Richard J. Mathar 称为org.nevec.rjm,这是类的包。
他们的实现为二项式方法提供了两个签名:int,int 和 BigInteger,BigInteger。
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.
使用 hashmap 改进 @dimo414 的解决方案:
Using a hashmap to improve @dimo414 's solution:
根据公式:n!/ ((nk)! * k!)
如果我们简单地计算分子和分母,许多计算将被浪费,并且可能“int”,“float”甚至“BigInteger”的范围可以填充。
因此,为了克服这种情况,我们可以在乘以值之前取消这些内容。
假设n=6,k=3
=> 6*5*4*3*2*1 / ((3*2) * (3*2))
假设如果我们乘以分子,则可以填充范围。更好的选择是在将值相乘之前将其取消。
在这种情况下——>
如果我们取消一切,我们只剩下:
(2*5*2)
乘以这些值要容易得多,并且需要更少的计算。
=================================================== ====
下面提到的代码对于以下数字将“有效”工作:
n=1000, k=2
n 的值
也许代码还可以改进。
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:
n=1000, k=2
the value of n
Probably the code can be still improved.
已经有很多解决方案提交了。
某些解决方案未考虑整数溢出。
某些解决方案在给定 n 和 r 的情况下计算所有可能的 nCr。
结果是需要更多的时间和空间。
大多数情况下我们需要直接计算nCr。我将分享另一种解决方案。
Already there are a lots of solutions submitted.
Some solution didn't consider integer overflow.
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.
我们还可以利用以下事实:
我们仍然需要计算 k!,而不是递归地实现 n 选择 k(这对于大数可能会变慢),但这可以比递归方法更快地完成。
请注意,上面的 select 方法假设 n 和 k 都不为负数。此外,长数据类型可能会因足够大的值而溢出。如果结果分别应使用 BigInteger 版本。分子和/或分母预计超过 64 位。
Instead of implementing n choose k recursively (which can get slow with large numbers), we can also make use of the fact that:
We still need to calculate k!, but this can be done much faster than the recursive method.
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.
编辑自几年前我所做的答案,其中 a、b 和 c 是整数,整数溢出使该方法严重无法使用。就可靠性而言,这个并没有真正更好,但它很懒。
如果值超过多头的限制,这也会变砖......除非您试图为学校项目或其他东西找到一些快速解决方案,否则不太可行。
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.