Java 有效地计算大n的nCr(n,m)mod k
我需要计算大型Java 有效地计算大n的nCr(n,m)mod k,java,performance,dynamic-programming,number-theory,Java,Performance,Dynamic Programming,Number Theory,我需要计算大型n(n)的nCr(n,m)%k,因为nPr有一个明确的公式nPr(n,m)=n!/((n-m)!),你应该尝试使用它。我的建议是: 记住n!=n*(n-1)*…*2*1 请注意,while循环(是的,循环,而不是递归^^^)可以极大地优化计算(除法消除了许多因子,留下一个乘法nPr(n,m)=n*(n-1)*…*(n-m+2)*(n-m+1)) 最后,应在计算nPr(n,m)后计算模,以避免冗余模运算 如果有帮助的话,您可以尝试公式化,这是一个对于n和m的所有有效值都应该为真的
n
(n)的nCr(n,m)%k
,因为nPr有一个明确的公式nPr(n,m)=n!/((n-m)!)
,你应该尝试使用它。我的建议是:
- 记住n!=n*(n-1)*…*2*1
- 请注意,while循环(是的,循环,而不是递归^^^)可以极大地优化计算(除法消除了许多因子,留下一个乘法
nPr(n,m)=n*(n-1)*…*(n-m+2)*(n-m+1)
)
最后,应在计算nPr(n,m)后计算模,以避免冗余模运算
如果有帮助的话,您可以尝试公式化,这是一个对于n
和m
的所有有效值都应该为真的语句
希望这有帮助:)
编辑
在我写下答案后,我意识到你说的是nCr。对于nCr,您可以在计算nPr后添加另一个while循环,它只计算m代码>,将nPr除以m编码>,然后对该答案进行模运算。总之,这将产生一个O(n)算法,它是相当可伸缩的。它使用的内存也非常少。这在编程竞赛中时不时出现,解决这一问题的一种常见方法是使用Lucas和中国剩余定理
@DAle发布了一个有用的资源,其中有详细信息:你不是几分钟前就发布了这个问题吗?前一个问题并不精确,它明确地询问了关于记忆的问题,而这里的情况并非如此,相反,我要求输入信息,以有效地解决计算nPr(n,m)%k
这一更普遍的问题(不一定是备忘录,很可能不会)。有一件事可能会节省一些内存使用量,那就是将k
外部化,因为它不会在递归过程中发生变异。这将节省内存,因为在您的情况下,您无法利用尾部递归。因此,每次它递归时,它都会保留每次保存3个新int
s的所有堆栈帧。它保存这些帧il返回。如此有效地,外部化k
将减少约1/3的内存使用。@CraigR8806好的一点,我更关心的是运行时tho。对于nPr和nCr的事情,很抱歉,对于您的方法,它对于大输入来说效率太低。中国剩余定理()我怀疑这就是我要找的。我目前正试图弄清楚我到底需要如何使用它。@AnnaVopureta算法怎么效率太低了?你可以在开始乘法之前做所有的消去运算。然后做乘法mod n。很抱歉反应太晚了。我不认为中国剩余定理是你可以理解的你在寻找一个O(1)算法吗?代价是计算n!。如果你能找到一种用O(1)计算的方法,那么结果也将是O(1)。否则,您将不得不完全重新考虑这一点,并放弃使用nCr的定义。也许有一个数学定理适合你的需要?希望这有帮助:)@Simon Sirak问题可以通过分解k来解决,然后通过应用Lucas定理将k替换为每个找到的因子来解决问题,然后通过应用CRT将结果组合在一起。DAle提供了更详细的描述:@Henry即使在取消之后,乘法对于大输入来说也太昂贵了。
int choose(int n, int m, int k) {
if (n==m || m==0)
return 1 % k;
return (choose(n-1, m-1, k) + choose(n-1, m , k)) % k;
}