不要被阶乘吓到(beauty of programe)

问题一:给定一个整数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;  

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值