LintCode题解(2)--尾部的零

来源:互联网 发布:结婚网络请柬 编辑:程序博客网 时间:2024/05/29 17:34

问题描述

设计一个算法,计算出n阶乘中尾部 0 的个数

样例

11! = 39916800,因此应该返回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},因为能被 2 整除的数出现的频率比能被 5 整除的数高的多,所以 M = z。所以原问题可以转化为 1 ~ n 所有的数中,一共含有多少个质因子 5 。这里我们利用下面的公式求解:
z = n/5 + n/52 + n/53 + …(这不会是一个无穷的运算,总存在一个 k,使得 5k > n,n/5k = 0)

理解起来就是 1 ~ n 中有 n/5 个数,这每个数都能贡献一个 5,然后 1 ~ n 中有 n/52 个数,这每个数又能贡献一个 5 …以此类推。
以上分析参考自《编程之美》。

解题代码

class Solution { public:    // param n : description of n    // return: description of return     long long trailingZeros(long long n) {        long long count = 0;        while(n){            count += n / 5;            n /= 5;        }        return count;    }};

扩展进阶

求 n! 的二进制表示中最低位 1 的位置。(规定最右的位置为位置 0)
最低位的 1 在哪个位置上,取决于 1~n 的数中有多少个质因子 2,因为只要出现一个质因子 2,最低位的 1 就会向左位移一位,利用下面的公式求解:
质因子 2 的总个数 = n/2 + n/4 + n/8 + …

long long lowestOne(long long n) {    long long res = 0;    while(n){        n >>= 1;        res += n;    }    return res;}

另外还可以通过下面这个规律求解:
n! 含有质因子 2 的个数还等于 n 减去 n 的二进制表示中 1 的数目。 下面来证明这个结论:
我们把 n 的二进制表达式中 1 的个数记为 m,也就是要证明 n/2 + n/4 + n/8 + … = n - m,因为除法结果是向下取整,所以左边的式子加的最后一个非零数为 1,根据等比数列求和公式 s = (首项 - 末项 * 公比)/(1 - 公比),可以得到 n/2 + n/4 + n/8 + … + 1 = n - 1。
如果在n的二进制表达中有 m 个 1,那么 n = k1 + k2 + … + km,其中 k 等于 2 的某次方,所以 n/2 + n/4 + n/8 + … = (k1 + k2 + … + km)/2 + (k1 + k2 + … + km)/4 + … = k1/2 + k1/4 + k1/8 + … +1 + k2/2 + k2/4 + … + 1 + … +km/2 + km/4 + … + 1 = k1 - 1 + k2 - 1 + … + km - 1 = n - m。即证!

long long lowestOne2(long long n) {    long long count = 0;    long long temp = n;    while(temp){        temp &= (temp - 1);        count++;    }    return n - count;}
原创粉丝点击