LintCode题解 —— 2. 尾部的零

描述

设计一个算法,计算出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 / 5 2 + n / 5 3 + . . . (这不会是一个无穷的运算,总存在一个 k,使得 5 k > 0 n / 5 k = 0 )

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

解题代码

#include <iostream>

using namespace std;

class Solution {
public:
    /*
     * @param n: A long integer
     * @return: An integer, denote the number of trailing zeros in n!
     */
    long long trailingZeros(long long n) {
        // write your code here, try to do it without arithmetic operators.
        long long re = 0;
        while(n){
            re += n / 5;
            n /= 5;
        }
        return re;
    }
};

int main()
{
    Solution solution;
    long long n;
    cin >> n;
    cout << solution.trailingZeros(n) << endl;
    return 0;
}

扩展进阶

求 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

如果一个整数k正好为2的某次方(即 k = 2 i ),那么求和公式
k / 2 + k / 4 + k / 8 + . . . = k / 2 + k / 4 + k / 8 + . . . + 1
根据等比数列求和公式 s = (首项 - 末项 * 公比)/(1 - 公比),可以得到 k / 2 + k / 4 + k / 8 + . . . + 1 = n 1

如果在n的二进制表达中有 m 个 1,那么 n = k 1 + k 2 + . . . + k m ,其中 k i = 2 i ,所以
n / 2 + n / 4 + n / 8 + = ( k 1 + k 2 + + k m ) / 2 + ( k 1 + k 2 + + k m ) / 4 + = ( k 1 / 2 + k 1 / 4 + k 1 / 8 + + 1 ) + ( k 2 / 2 + k 2 / 4 + + 1 ) + + ( k m / 2 + k m / 4 + + 1 ) = ( k 1 1 ) + ( k 2 1 ) + + ( k m 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;
}

猜你喜欢

转载自blog.csdn.net/u013507678/article/details/80433992