• 【数学】阶乘函数后 K 个零


    题目描述

    f(x)是x!末尾是 0 的数量。回想一下x! = 1 * 2 * 3 * ... * x,且 0! = 1。

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

    示例 1:

    输入:k = 0
    输出:5
    解释:0!, 1!, 2!, 3!, 和 4!均符合 k = 0 的条件。

    解题思路 

    第一种思路,这个解法会超时,理解起来比较简单:

    • 由于2出现的次数大于5出现的次数,那么统计5出现的次数就是末尾是 0 的数量。
    • 考虑5*(1到N,这里用i表示)的数量,那么 只需要判断i 是不是5的倍数,出现一次5的倍数就加1.
    private int count5(int i) {
    
        int count = 1;
        while (i % 5 == 0) {
            i /= 5;
            count++;
        }
        return count;
    }

    有了上述思路后代码实现如下:

    1. class Solution1 {
    2. public int preimageSizeFZF(int k) {
    3. int count5 = 0;
    4. int i = 0;
    5. while (count5 < k) {
    6. i++;
    7. count5 += count5(i);
    8. }
    9. if (count5 == k) {
    10. return 5;
    11. } else {
    12. return 0;
    13. }
    14. }
    15. private int count5(int i) {
    16. int count = 1;
    17. while (i % 5 == 0) {
    18. i /= 5;
    19. count++;
    20. }
    21. return count;
    22. }
    23. }

    第二种思路,这种思路其实是求解出现N这个数字的第一次所在位置,这里会使用到二分查找;由于考虑的是第一次N的位置,那么如果这个N不存在则会找到第一个大于N的位置;同理N+1的位置也可以这么找到;用f(N) 表示第一个大于等于N的数字,f(N+1)表示第一个大于等于N+1的数字,最终: 如果N存在那么 f(N+1)-f(N) =5 , 如果N不存在那么 f(N+1)-f(N) =0;

    • 首先计算从 (1-num) 可以出现多少次5;
    private int count5(int num) {
        int count = 0;
        while (num >= 5) {
            num /= 5;
            count += num;
        }
        return count;
    }
    • 接着使用二分查找,从0 到 N*5 找到第一个大于N的位置;
    public int getValue(int k) {
    
        int left = 0;
        int right = k * 5;
    
        while (left <= right) {
    
            int mid = (right - left) / 2 + left;
    
            int count = count5(mid);
            if (count < k) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
    
        }
        return left;
    }
    • 最后执行f(N+1)-f(N)
    public int preimageSizeFZF(int k) {
        return (getValue(k + 1)) - (getValue(k));
    }

    整体代码如下:

    1. class Solution {
    2. public int preimageSizeFZF(int k) {
    3. return (getValue(k + 1)) - (getValue(k));
    4. }
    5. public int getValue(int k) {
    6. int left = 0;
    7. int right = k * 5;
    8. while (left <= right) {
    9. int mid = (right - left) / 2 + left;
    10. int count = count5(mid);
    11. if (count < k) {
    12. left = mid + 1;
    13. } else {
    14. right = mid - 1;
    15. }
    16. }
    17. return left;
    18. }
    19. private int count5(int num) {
    20. int count = 0;
    21. while (num >= 5) {
    22. num /= 5;
    23. count += num;
    24. }
    25. return count;
    26. }
    27. public static void main(String[] args) {
    28. Solution solution = new Solution();
    29. //1000000000
    30. System.out.println(solution.preimageSizeFZF(1000000000));
    31. System.out.println(solution.preimageSizeFZF(5));
    32. }
    33. }

    结果耗时比对,两次效果:

    总结 

    如果只是单纯解决这道题,解决思路会非常多,但是耗时差别会非常大;第二种思路我是看其他人的解法才解出来的,第二种思路的核心就是通过二分查找找到第一个满足条件的数字或者是大于条件的数字,然后用f(n+1)-f(n) 就能求出满足条件的个数。

  • 相关阅读:
    Python爬虫入门教程之快速理解HTTP协议
    关于进程同步与互斥的一些概念(锁、cas、futex)
    angular记录
    《动手学深度学习》(pytorch版+mxnet版)2023最新
    华为OD机试 - 数据最节约的备份方法 - 二分查找(Java 2023 B卷 100分)
    智能优化算法:白鲸优化算法-附代码
    宏观经济学复习题
    nginx详解
    强扩展、强一致、高可用…GaussDB成为游戏行业的心头爱
    使用Nacos作为配置中心
  • 原文地址:https://blog.csdn.net/weiliuhong1/article/details/126574254