前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Leetcode No.172 阶乘后的零

Leetcode No.172 阶乘后的零

作者头像
week
发布2021-05-06 16:02:40
3670
发布2021-05-06 16:02:40
举报
文章被收录于专栏:用户画像

题目描述

给定一个整数 n,返回 n! 结果尾数中零的数量。

示例 1: 输入: 3 输出: 0 解释: 3! = 6, 尾数中没有零。

示例 2: 输入: 5 输出: 1 解释: 5! = 120, 尾数中有 1 个零. 说明: 你算法的时间复杂度应为 O(log n) 。

思路一:计算阶乘

这种方法速度太慢了,但却是一个好的起点。虽然不会在面试中实现它,但是你可以简单的描述它是个解决问题的办法之一。

解决这个问题的最简单的办法就是计算 n!,然后计算它的末尾数 0 个数。阶乘是通过将所有在 1和 n 之间的数字相乘计算的。例如,10!=10⋅9⋅8⋅7⋅6⋅5⋅4⋅3⋅2⋅1=3,628,800。因此,可以使用以下算法迭代计算阶乘。

如果一个数字末尾有零,那么它可以被 10 整除。除以 10 将删除该零,并将所有其他数字右移一位。因此,我们可以通过反复检查数字是否可以被 10 整除来计算末尾 0 的个数。

在 Java 中,我们需要使用 BigInteger,防止在计算阶乘的过程中溢出。

代码语言:javascript
复制
import java.math.BigInteger;
class Solution {
    public int trailingZeroes(int n) {
        BigInteger nFactorial=BigInteger.ONE;
        for(int i=1;i<=n;i++){
            nFactorial = nFactorial.multiply(BigInteger.valueOf(i));
        }
        int cnt=0;
        while(nFactorial.mod(BigInteger.TEN).equals(BigInteger.ZERO)){
            nFactorial=nFactorial.divide(BigInteger.TEN);
            cnt++;
        }
        return cnt;
    }
}

复杂度分析

时间复杂度:O(n)。

空间复杂度:O(1)。

思路二

首先末尾有多少个 0 ,只需要给当前数乘以一个 10 就可以加一个 0。

再具体对于 5!,也就是 5 * 4 * 3 * 2 * 1 = 120,我们发现结果会有一个 0,原因就是 2 和 5 相乘构成了一个 10。而对于 10 的话,其实也只有 2 * 5 可以构成,所以我们只需要找有多少对 2/5。

我们把每个乘数再稍微分解下,看一个例子。

11! = 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 = 11 * (2 * 5) * 9 * (4 * 2) * 7 * (3 * 2) * (1 * 5) * (2 * 2) * 3 * (1 * 2) * 1

对于含有 2 的因子的话是 1 * 2, 2 * 2, 3 * 2, 4 * 2 ...

对于含有 5 的因子的话是 1 * 5, 2 * 5...

在这里插入图片描述
在这里插入图片描述

含有 2 的因子每两个出现一次,含有 5 的因子每 5 个出现一次,所有 2 出现的个数远远多于 5,换言之找到一个 5,一定能找到一个 2 与之配对。所以我们只需要找有多少个 5。

直接的,我们只需要判断每个累乘的数有多少个 5 的因子即可。

代码语言:javascript
复制
class Solution {
    public int trailingZeroes(int n) {
        int cnt=0;
        for(int i=0;i<n;i++){
            int factor=i;
            while(factor>0){
                cnt=cnt+factor/5;
                factor=factor%5;
            }
        }
        return cnt;
    }
}

但发生了超时,我们继续分析。

对于一个数的阶乘,就如之前分析的,5 的因子一定是每隔 5 个数出现一次,也就是下边的样子。

n! = 1 * 2 * 3 * 4 * (1 * 5) * ... * (2 * 5) * ... * (3 * 5) *... * n

因为每隔 5 个数出现一个 5,所以计算出现了多少个 5,我们只需要用 n/5 就可以算出来。

但还没有结束,继续分析。

... * (1 * 5) * ... * (1 * 5 * 5) * ... * (2 * 5 * 5) * ... * (3 * 5 * 5) * ... * n

每隔 25 个数字,出现的是两个 5,所以除了每隔 5 个数算作一个 5,每隔 25 个数,还需要多算一个 5。

也就是我们需要再加上 n / 25 个 5。

同理我们还会发现每隔 5 * 5 * 5 = 125 个数字,会出现 3 个 5,所以我们还需要再加上 n / 125 。

综上,规律就是每隔 5 个数,出现一个 5,每隔 25 个数,出现 2 个 5,每隔 125 个数,出现 3 个 5... 以此类推。

最终 5 的个数就是 n / 5 + n / 25 + n / 125 ...

写程序的话,如果直接按照上边的式子计算,分母可能会造成溢出。所以算 n / 25 的时候,我们先把 n 更新,n = n / 5,然后再计算 n / 5 即可。后边的同理。

代码语言:javascript
复制
class Solution {
    public int trailingZeroes(int n) {
        int cnt=0;
        while(n>0){
            cnt+=n/5;
            n=n/5;
        }
        return cnt;
    }
}

复杂度分析

时间复杂度:O(logn)。在这种方法中,我们将 n 除以 5 的每个幂。根据定义,5 的log5 N幂小于或等于 n。由于乘法和除法在 32 位整数范围内,我们将这些计算视为 O(1)。因此,我们正在执行 log5 N⋅O(1)=logn 操作 空间复杂度:O(1),只是用了常数空间。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/03/21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目描述
  • 思路一:计算阶乘
  • 思路二
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档