编程之美:阶乘数计算

1.问题描述

1).给定一个整数N,那么N的阶乘N!末尾有多少个0?例如:N=0,N!=3628800,N!的末尾有两个0.

2).求N!的二进制表示中最低1的位置

 

2.分析与解法

首先考虑,如果N! = K*10M,且K不能被10整除,那么N!末尾有M个0.再考虑对N!质因分解,N! = (2X)*(3Y)*(5Z)...,由于10=2*5,所以M只跟X和Z有关,每一对2和5都可以得到一个10,于是M=min(X,Z)。不难看出X大于等于Z,因为在N!分解的数种明显2出现的频率要高于5,所以把公式简化为M=Z。

根据上面的分析,有

 

对于问题1

解法一:计算Z,最直接的方法,就是计算ii =1, 2, …, N)的因式分解中5的指数,然后求和:

int lowNumzero1(int n)
{
    int i, j, ret = 0;
    
    for(i = 1; i <= n; i++)
    {
          j = i;
          while(j % 5 ==0)
          {
                  ret++;
                  j /= 5;
          }
    }
    
    return ret;
}

 

 

解法二:公式:Z = [N/5] +[N/52] +[N/53] + …(不用担心这会是一个无穷的运算,因为总存在一个K,使得5K > N,[N/5K]=0。)公式中,[N/5]表示不大于N的数中5的倍数贡献一个5,[N/52]表示不大于N的数中52的倍数再贡献一个5,……代码如下:

int lowNumzero2(int n)
{
    int ret = 0;
    
    while(n)
    {
           ret += n / 5;
           n /= 5;
    }
    
    return ret;
}

 

 

对于问题2

问题实际上等同于求N!含有质因数2的个数。即答案等于N!含有质因数2的个数加1。

解法一:由于N!中还有质因数2的个数,等于Z = [N/2] +[N/22] +[N/23] + …,所有有代码

int lowestOne(int n)
{
    int ret = 0;
    
    while(n)
    {
           n >>= 1;
           ret += n;
    }
    return ret;
}

 

 

解法二:

N!含有质因数2的个数,还等于N减去N的二进制表示中1的数目。

 

posted on 2012-08-17 09:58  as_  阅读(657)  评论(0编辑  收藏  举报

导航