现在的位置: 首页 > 综合 > 正文

编程之美-2.2-不要被阶乘吓倒

2018年05月02日 ⁄ 综合 ⁄ 共 817字 ⁄ 字号 评论关闭

题目:

1. 给定一个整数N,那么N的阶乘N!末尾有多少个0?

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

分析与解答:

对于题目1:

最简单直接的方法,算出N!再看10的倍数关系。复杂度虽然不高,但致命的问题是溢出。在N不到100的时候就会引起溢出,所以虽然这是一个正确的方法,但在实际中却不能使用。这时就需要算法来解决问题,通过其他的途径而不是先要计算N!而求出最后的结果。

考虑N!末尾的0是怎么来的:对N!进行因式分解,N!=(2^X)*(3^Y)*(5^Z)*...,N!中因子2和因子5相乘可以得到10的倍数,最末尾有1个0。所以0的个数M=min(X,Z),因为可被2整除的数比5出现频率高而且可分解的2的数量多,所以X>Z,所以M=Z。所以最终的问题转化为,求N!因式分解结果中5的个数。

解法1和解法2都是基于该推理给出的。解法1,直接从1遍历到N,找出5的倍数,并将分解的数量相加。复杂度为Omiga(n)

int ret = 0;
for(int i = 1; i <= N; i ++){
    int j = i;
    while(j % 5 == 0){
        ret ++;
        j /= 5;
    }
}

解法2基于该思想,但有所改进,Z=[N/5] + [N/5^2] + [N/5^3] + ... ,即不大于N的数中,5的倍数贡献1个5,,5^2的倍数又贡献1个5,这样将所有贡献的5累加起来就是最后质因数分解后5的数量。复杂度为Theta(log5(n))。

int ret = 0;
while(N){
    ret += N / 5;
    N /= 5;
}

对于题目2:

参考题目1,思考解题的本质。可以求,N!结果的二进制表示中末尾有多少个0,而二进制表示末尾如果是0,表示可以被2整除。所以该题其实是求N!中质因数2的数量。

这样可以使用题目1的解法2,求出该数。

int LowestOne(int N){
    int ret = 0;
    while(N){
        N >>= 1;    //N缩小为原来的1/2,继续操作
        ret += N;   //N除以2的结果         
    }
    return ret + 1;
} 

抱歉!评论已关闭.