问题一:给定一个整数N,求该整数的阶乘中末尾含有多少个0?例如:N=10;N!=3628800,N!的末尾含有两个0.
问题二:求N!的二进制表示中最低位1的位置
阶乘:是所有小于和等于该数的正整数的乘积,自然数N的阶乘是N!,这一表示法是基斯顿 卡曼引入的。阶乘定义为:一种数学计算方式。用比给定数值(必定大于等于零)小的自然数依次相乘直到最终因数为给定数值为止。记作“N!”。例如 5 的阶乘记作 5!,即 1×2×3×4×5=120。
实现一递归:
int fun1(int num)
{
if (num<0)
{
cout<<"error\n";
}
else
{
if (num==0||num==1)
{
return 1;
}
else
{
return num*fun1(num-1);
}
}
}
实现二非递归:
int fun2(int num)
{
if (num<0)
{
cout<<"error\n";
}
else
{
if (num==0||num==1)
{
return 1;
}
else
{
int sum=1;
for (int i=1;i<=num;i++)
{
sum*=i;
}
return sum;
}
}
}
问题一解法:
如果N!= K×10M,且K不能被10整除,那么N!末尾有M个0。再考虑对N!进行质因数分解,N!=(2^x)×(3^y)×(5^z)…,由于10 = 2×5,所以M只跟X和Z相关,每一对2和5相乘可以得到一个10,于是M = min(X, Z)。不难看出X大于等于Z,因为能被2整除的数出现的频率比能被5整除的数高得多,所以把公式简化为M = Z。
方法1:计算Z,就是计算结果里面含有5的指数,即求1到N中每个数含有的5的指数,最后求和。
ret = 0;
for(i = 1; i <= N; i++)
{
j = i;
while(j % 5 ==0)
{
ret++;
j /= 5;
}
}
方法2:z = [N/5] + [N/(5*5)] + [N/(5*5*5)].... */
/* [N/5]为N中5的个数,[N/(5*5)]为[N/5]中5的个数 */
/* Z为N!中含有质数5的个数 */
公式中,【N/5】表示不大于N的整数中5的倍数贡献一个5,[N/(5*5)] 表示不大于n的整数中25的数贡献一个5,最后求和。
ret = 0;
while(N)
{
ret += N / 5;
N /= 5;
}
问题二解法:
将一个数除以2,若为零说明尾部为0,右移一位;反之若为1,则说明这个二进制数是奇数,无法被2整除。所以问题二实际上等同于求N!中含有质因数2的个数,即结果右移多少位之后不能再被2整数。
int ret = 0;
while (n)
{
n >>= 1;
ret += n;
}
return ret + 1;