不要被阶乘吓到
这一节有两个问题:
- 给定一个整数N,那么N的阶乘N!末尾有多少个0?
- 求N!的二进制表示中最低位1的位置。
对于第一个问题,其实就是计算N!中有多少个质因子5,因为所有的0末尾的0都是5和偶数相乘产生的,而偶数出现的频率要远远高于5出现的频率,所以只要计算N!中又多少个5。最直接的向下面到的代码:
intFunc1(intn)
{
intcount = 0;
for(inti=n; i>0; i--)
{
inttemp = i;
while(temp % 5==0)
{
count++;
temp /= 5;
}
}
returncount;
}
上面的代码复杂度很高,要降低复杂度可以对N循环的除以5的一次方,二次方……,直到N为0,N!包含的5个数=N/5+N/5二次方+N/5三次方……
intFunc2(intn)
{//n/k表示了不大于n的正整数能被k整除的个数
// 对于5的m次方来说分别被5的一次方到m次方统计一次,也就统计了m次
intcount = 0;
while(n){
count += n/5;
n/=5;
}
returncount;
}
问题2其实就是计算N!的二进制表示中最后有几位0,也就是计算N!中含有质因数2的个数
intFunc3(intn)
{
intcount=0;
while(n)
{
count += n/2;
n/=2;
}
returncount;
}
编程之美中还提到了一个不容易察觉的规律:N!中2的个数 = N-N中1的个数
intOneCount(intn)
{
intcount = 0;
while(n)
{
n &= n-1;
count++;
}
returncount;
}
intFunc4(intn){//N!中包含质因数2的个数=n-n的二进制表示中1的个数
returnn-OneCount(n);
}
相关题目:判断N是否是2的方幂,
boolis2N(intn)
{
returnn>=0&& (n&(n-1) == 0);
}
在做这些程序的时候在网上还看到了一些比较好玩的题目,都是和位运算相关的,顺便贴一下
//比较两个数是否相等
intIsEqual(inta,intb)
{
return!(a^b);
}
//逻辑右移N位
intLogicalShift(intx,intn)
{
intmask = ~((1<<31) >> (n-1));
return(x >> n) & mask;
}
//如果一个数的二进制中含有奇数个1返回1,否则返回0
intBitParity(intn)
{
intret = (n>>16)^n;
ret = (ret>>8) ^ ret;
ret = (ret>>4) ^ ret;
ret = (ret>>2) ^ ret;
ret = (ret>>1) ^ ret;
returnret & 1;
}
//完成!运算
intQuFan(intn)
{
intret = (n>>16)|n;
ret = (ret>>8) | ret;
ret = (ret>>4) | ret;
ret = (ret>>2) | ret;
ret = (ret>>1) | ret;
return(~ret) & 1;
}