我最近以节省时间和空间的方式看到了二项式系数的代码。
ll C(ll n,ll k)
{
ll p=1;
if(k>n-k)
k=n-k;
for(int i=0;i<k;i++)
{
p*=(n-i);
p/=(i+1);
}
return p;
}
让我们考虑以下三种不同的方法。
情况1:
for(int i=0;i<k;i++)
{
p*=(n-i);
p/=(i+1);
}
情况2:
for(int i=0;i<k;i++)
{
p*=(n-i)/(i+1);
}
情况3:
for(int i=0;i<k;i++)
p*=(n-i);
for(int i=0;i<k;i++)
p/=(n-i);
在情况1和情况3中答案都是正确的,在情况2中,答案是不同的。 但是只有情况3才能给出正确的答案,而在这两种情况下,分数和分数都不会在乘法之后由于除法而被删除。
有人可以向我解释这个东西吗?
答案 0 :(得分:2)
考虑案例1:
for(int i=0;i<k;i++)
{
p*=(n-i); //statement 1
p/=(i+1); //statement 2
}
在第一次迭代中,它将是整数除法,因为i
为1。
在第二次迭代中,在语句1中,p
将是奇数和偶数(因为它们是连续的)的乘积,因此将在语句2中被2整除。
在第三次迭代中,在语句1中,p
将是三个连续数字按降序排列的乘积,因此将在语句2中被3整除。
依此类推...
考虑案例2:
失败是因为整数除法首先在语句的rhs中执行
p*=(n-i)/(i+1);
这会导致截断,并且您已经正确地推测了这一点。
考虑案例3: 我相信您的代码应为:
for(int i=0;i<k;i++)
p*=(n-i);
for(int i=0;i<k;i++)
p/=(i+1);
在这里,我们看到的情况与情况1相似,但这很明显。 您先以降序(最多k)然后之后的顺序将连续整数相乘 将其除以整数乘积(最多k)。这是二项式系数的公式,可以给出正确的结果。
注意:由于案例3 在除法开始之前具有连续的乘法,所以可能会出现溢出。因此,案例1 是首选。
答案 1 :(得分:1)
在处理整数算术时,评估顺序很重要。
稍微改一下您的案子,
1:先乘
p = (p * (n-i)) / (i+1)
和2:首先划分
p = p * ((n-i) / (i+1))
如果n-i
小于i+1
,则(n-i)/(i+1)
为零。
因此,您的情况2将得出零,而情况1则不会。
例如,如果您有
int x = 2;
然后x *= 3/4;
导致x
为0,但在x *= 3; x /= 4;
之后为1。
您的情况3必须是错字,但也是“先乘”的情况。