[每日一题] leetcode 793. 阶乘函数后 K 个零

167 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

阶乘函数后 K 个零

 f(x) 是 x! 末尾是0的数量。回想一下 x!=123...x,且0!=1 。 f(x) 是 x! 末尾是 0 的数量。回想一下 x! = 1 * 2 * 3 * ... * x,且 0! = 1 。 例如, f(3)=0 ,因为3!=6的末尾没有0例如, f(3) = 0 ,因为 3! = 6 的末尾没有 0 ; f(11)=2 ,而 f(11) = 2 , 因为11!=39916800末端有20因为 11!= 39916800 末端有 2 个 0 。 给定 k,找出返回能满足f(x)=k 的非负整数x 的数量。给定 k,找出返回能满足 f(x) = k 的非负整数 x 的数量。

示例 1:
输入:k = 0
输出:5
解释:0!, 1!, 2!, 3!, 和 4! 均符合 k = 0 的条件。
示例 2:
输入:k = 5
输出:0
解释:没有匹配到这样的 x!,符合 k = 5 的条件。
示例 3:

输入: k = 3
输出: 5

 

数据范围:
  • 0 <= k <= 10^9
思路

阶乘末尾的0如何求出?
显然,0的个数和 2x×5y2^x \times 5^y 中的 min(x,y)min(x, y) 有关
每出现一对这样的数,就多一个0
2 需要考虑吗?
2出现的次数一定比5出现的次数多,这个是毋庸置疑
所以就可以把问题转化为 看5的幂次 如何比较快的求出来呢
考虑这样的算式
cnt(x)=x/5+cnt(x/5)cnt(x) = x / 5 + cnt(x / 5) 就可以把x里面的因子全部除干净
因为这个等价于
cnt(x)=x5+x52+x53+...+x5kcnt(x) = \frac{x}{5} + \frac{x}{5^2} + \frac{x}{5^3} + ... + \frac{x}{5^k} 算出来以后就知道当前数的阶乘的0有多少个了
然后,我们就可以二分去找到最接近的一个数了
显然二分也存在这样一种情况,我找不到这个数,并不存在0为x的数 这个时候返回0即可 若是找到了这个样子的一个数,那么这样的数必定不会超过5个
因为 设当前数为x,则有x,x+1,x+2,x+3,x+4,x+5 设当前数为 x, 则有 x, x + 1, x + 2, x + 3, x + 4, x + 5 ((x+5)x)/5=1 则 ((x + 5) - x) / 5 = 1 所以成立条件的最大的数字应该只能有5个数字
二分的时候有很多种形式,这里我采取的是逼近他的下届,其实若是逼近上界也是一样的。
且本体的答案有一点数论分块的意思
所以上界下届都可

代码
class Solution {
public:
    int preimageSizeFZF(int k) {
        #define int long long
        int l = 0, r = 5e9;
        auto get = [](auto&& self, int x) -> int {
            if (x / 5) return x / 5 + self(self, x / 5);
            else return 0;
        };
        while (l < r) {
            int x = l + r >> 1;
            if (get(get, x) < k) l = x + 1;
            else r = x; 
        }
        if (get(get, r) == k) return 5;
        #undef int
        return 0;
    }
};