阶乘末尾0的数量

200 阅读2分钟

描述

给定一个非负整数 n ,返回 n! 结果的末尾为 0 的数量。

n! 是指自然数 n! 的阶乘,即 : N!=1×2×3…(N−2)×(N−1)×NN!=1×2×3…(N−2)×(N−1)×N。

特殊的,  0 的阶乘是 1 。

数据范围: 0<n≤10140<n≤1014

进阶:空间复杂度 O(1)O(1),时间复杂度 O(logn)O(logn)

复杂度要求:

不大于 O(log⁡n)O(logn)

示例1

输入:

3

返回值:

0

说明:

3!=6     

示例2

输入:

5

返回值:

1

说明:

5!=120    

示例3

输入:

1000000000

返回值:

249999998

思路

  • 题目要求计算阶乘末尾0的数量,最直接的方法就是通过计算n!,得出其值,然后在逐个的找出末尾的0,得出末尾0的数量;
  • 考虑到N的范围比较大,使用long会溢出,所以采用Java中BigDecimal来进行阶乘的运算;
  • 得出阶乘的结果后,再将数值转换成字符串,从尾部开始遍历,找出末尾所有的零。

代码

import java.math.BigDecimal;
public class Solution {
  /**
   * the number of 0
   * @param n long长整型 the number
   * @return long长整型
   */
  public long thenumberof0 (long n) {
      // 使用BigDecimal来存储乘积
      BigDecimal multi = new BigDecimal(String.valueOf(1));
      // 实现阶乘运算
      while(n > 1){
          BigDecimal bb = new BigDecimal(String.valueOf(n));  
          multi = multi.multiply(bb);
          --n;
      }
      // 找出末尾零的的个数
      int count = 0;
      String str = String.valueOf(multi);
      for (int i = str.length()-1;i >= 0;--i){
          if (str.charAt(i) != '0'){
              break;
          }
          ++count;
      }
      return count;
  }
}

方法二

思路

  • 由于N的范围比较大,所以采用方法一可能会导致程序运行超时,无法啊完美解决问题,需要考虑降低时间复杂度,从而提高程序运行速度;
    图片说明
    图片说明
    图片说明
    图片说明
  • 观察10以内的数字的互乘,可以发现只有2 * 5 = 10会产生0,也就是说两个数相乘会产生0,则这两个数中必有因子5和2,且5的个数一定是小于2的个数的,所以要找出一个阶乘n!末尾0的数量,只需要找出从1~n这n个数中总共有多少个因子5;
  • 但是,从1遍历到n每个数看一下它能除多少次5是不行的。因为n的数据范围是1e18,遍历1e18个数运行时间过大。
  • 其实存在如下公式:5的数量count = n/5+n/25+……+n/5+……;
  • 那么这公式是什么意思呢?n/5即阶乘中所有至少含有一个因子5的个数,而n/25即阶乘中所有至少含有两个因子5的个数,由于在n/5中已经统计一次n/25了,所以只需要在加一次n/25即可,以此类推,从而得出n的阶乘中因子5的个数。
  • 故可以依据此公式进行计算末尾0的数量。
  • 代码
import java.math.BigDecimal;
public class Solution {
  /**
   * the number of 0
   * @param n long长整型 the number
   * @return long长整型
   */
  public long thenumberof0 (long n) {

      long count = 0;
      long base = 5;
      while(n >= base){
          count = count + n / base;
          base *= 5;
      }
      return count;
  }
}