这是来自 CodeSprint3 https://cs3.interviewstreet.com/challenges/dashboard/#problem/50877a587c389 的问题基本上问题是计算给定 n 和 r 的可能组合的数量 nCr。此外,1 <= n < = 1000000000 和 0 <= r <= n。以 142857 为模输出所有答案。
Since 6C4=6!/4! 2!
=6*5/2!
=6*5/2*1
我认为可以在每一步使用除法来避免溢出。也就是说,从 n 的值开始(在这种情况下,n 为 6)。将 n 递减并乘以之前的值(因此变为 6*5) 用分母进行除法,然后将其递减(6*5 /2 并且分母 2 变为 1)重复这些步骤,直到 n 小于 2 个分母的最大值并且在相同次数的迭代中除数(分母的最小值将变为 1)
int count(int n,int r)
{int maxDen=r>(n-r)?r:n-r; //larger number in the denominator
int minDen=n-maxDen; //the smaller number in denominator
double num=1;
for(int j=n;j>maxDen;j--)
{num=j*num; //for C(6,4) example num=6*5 and so on
// System.out.println("num "+num +" minDen "+minDen);
num=num/minDen; //divide num 6*5 in this case by 2
minDen--;
}
num=num%142875; //output the result modulo 142875
return (int) num;
}
但可能是由于执行更多除法时精度损失,它给出了错误的值,但它仍然为某些值提供了正确的输出。因为它对 22 17 表示正确,但对 24 17 则不正确。
(22 17) = 26334 //gives Correct value
(24 17)= 60353 //wrong value correct value is 60390
(25,17)=81450 //wrong value correct value is 81576
(16 15)= 16 //gives correct value
(87 28)= 54384 //wrong value correct value is 141525
我尝试将 num 用作 BigDecimal,因此我必须用 BigDecimal 替换所有内容来执行操作。然后输出与在上述代码中给出正确结果的输入相同。但对于给出错误结果的输入,程序抛出异常
Exception in thread "main" **java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.**
at java.math.BigDecimal.divide(Unknown Source)
at Combination.NcRcount2.count(NcRcount2.java:16)
at Combination.NcRcount2.main(NcRcount2.java:37)
第 16 行是 num=num.divide(minDen); //代替之前使用的 num/minDen,在这种情况下 num 和 minDen 都是 BigDecimal
即使该数字没有精确的十进制表示,考虑到 BigDecimal 的任意精度,如果它没有引发异常,结果中的错误也会被最小化。**如果浮点数或双精度数的除法结果没有精确的十进制表示,那么为什么不抛出异常?**
我使用 BigDecimal 和动态编程方法验证了结果
C(n,r)=C(n-1,r-1)+C(n-1,r)
在我看来,这在所有情况下都可以正常工作,但必须有更好的方法
BigDecimal Comb (int n, int k)
{ if(k>n-k)
k=n-k;
BigDecimal B[][]=new BigDecimal[n+1] [k+1];
for (int i = 0; i <= n; i++)
{ int min;
if(i>=k)
min=k;
else
min=i;
for (int j = 0; j <= min; j++)
{ if (j == 0 || j == i)
B[i][j] =new BigDecimal(1);
else{
if(j>i-j)
B[i][j]=B[i][i-j];
else
B[i][j] = B[i - 1][j - 1].add(B[i - 1] [j]);
}
}
}
BigDecimal div=new BigDecimal(142857);
return B[n][k].remainder(div);
}
请在不使用 BigDecimal 的情况下建议我一种更好的方法