【数学】阶乘函数后 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;
}

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


class Solution1 {
    public int preimageSizeFZF(int k) {
        int count5 = 0;

        int i = 0;
        while (count5 < k) {
            i++;
            count5 += count5(i);
        }

        if (count5 == k) {
            return 5;
        } else {
            return 0;
        }
    }

    private int count5(int i) {

        int count = 1;
        while (i % 5 == 0) {
            i /= 5;
            count++;
        }
        return count;
    }
}

第二种思路,这种思路其实是求解出现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));
}

整体代码如下:


class Solution {

    public int preimageSizeFZF(int k) {
        return (getValue(k + 1)) - (getValue(k));
    }

    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;
    }

    private int count5(int num) {
        int count = 0;
        while (num >= 5) {
            num /= 5;
            count += num;
        }
        return count;
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        //1000000000
        System.out.println(solution.preimageSizeFZF(1000000000));
        System.out.println(solution.preimageSizeFZF(5));
    }
}

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

总结 

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值