数字之魅:不要被阶乘吓倒

来源:互联网 发布:怎么查看软件注册表 编辑:程序博客网 时间:2024/06/03 15:59
题目1:给定一个整数N,那么N的阶乘N!末尾有几个0呢?
例如:N=10,N!=3628800;N!的末尾有两个0。

方案一:我们一般都会想到就算出完成的N!的阶乘的结果,再看有几个0。但是这样会涉及到值的溢出!
方案二:我们可以考虑不用完全计算出阶乘的结果,这样可以避免方案一中的溢出情况,也会使问题变得简单。我们可以从“哪些数相乘能得到10”的这个角度来考虑,问题就变的简单了!首先考虑,如果N=K*10^m,且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,所以我们只需要考虑Z的个数就行了。
方案一解法如下:要计算Z,最直接的方法,就是计算i(i=1,2...,n)的因式分解中5的指数,(1*2*3*4....*n),然后求和:
ret=0;for(i=1;i<=N;i++){   j=i;   while(j % 5==0)   {      ret++;      j/=5;   }}
由上可看出,循环中有许多不要的步骤,因为只需要求5的指数个数即可,上述还可以改进如下:
ret=0;for(i=1;i<=N;i*=5){   j=i;   while(j % 5==0)   {      ret++;      j/=5;   }}
方案二解法如下;Z=[N/5]+[N/5^2]+[N/5^3]+....(公式中[N/5]表示不大于N的数中5的倍数贡献一个)。
例如:N = 25 ,即1~25,5的倍数(5,10,15,20,25)贡献一个5,25的倍数贡献一个5,虽然25可以贡献两个5,但是已经在5的倍数中贡献一次了,所以这里就统计一次。也就是说,对于每一个5 ^M,N只统计一次5,虽然它本身有多个5的质因数,但是已经在前面M-1计算过,所以只需统计一次即可。
具体实现代码:
ret=0;while(N){  ret+=N/5;  N/=5;}
题目2:求N!的二进制中最低位1的位置。
例如N=3;N!=6.其二进制为0110.其二进制中1的最低位置为2。

方案一:这里我们可以通过统计质因数2的个数来求解:和上面的思路一样,N/2+N/4+N/8+N/16+..
具体实现代码:
int lowestOne(int N){   int Ret=0;   while(N)   {      N>>1;      Ret+=N;   }   return Ret+1;}
方案二:这里我们还可以根据N减去N的二进制中1的数目这个规律来求解。
其具体实现代码如下:
int count(int n)//统计1的个数;{int Ret=0;while( n ){Ret++;n= n&(n-1);}return Ret;}int FindLowestOne(int num)//num中最低位1的位置;{return num-count(num)+1;}
相关题目;给定整数n,判断它是否为2的方幂。
实现:
if(n & (n-1))==0)


0 0
原创粉丝点击