「前端刷题」172.阶乘后的零(MEDIUM)

132 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,点击查看活动详情

题目(Factorial Trailing Zeroes)

链接:https://leetcode-cn.com/problems/factorial-trailing-zeroes
解决数:969
通过率:48.6%
标签:数学 
相关公司:microsoft amazon baidu 

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

提示 n! = n * (n - 1) * (n - 2) * ... * 3 * 2 * 1

 

示例 1:

输入: n = 3
输出: 0
解释: 3! = 6 ,不含尾随 0

示例 2:

输入: n = 5
输出: 1
解释: 5! = 120 ,有一个尾随 0

示例 3:

输入: n = 0
输出: 0

 

提示:

  • 0 <= n <= 104

 

进阶: 你可以设计并实现对数时间复杂度的算法来解决此问题吗?

思路

本题如果算出阶乘值再数末尾几个 0 的话,测试用例中的数据在运算阶乘值时很容易超过 Number.MAX_SAFE_INTEGER 。所以本题需要找规律优化算法。

首先我们知道末尾有 0 是因为这个数是 10 的倍数(50 是 10 的倍数,500 是 100 的倍数,100 可以分解为 10 * 10)。也就是说在阶乘中有数相乘的乘积是 10,那么每多一个 10 结尾就会多一个 0。

另外可以发现在 9! 中唯一能产生 10 的乘积的就是 2 * 5 。而在 9! 中许多数都有 2 这个因子,也就是说在一段阶乘区间内,10 的乘积个数取决于能分解出 5 的个数。比如 15! 中数字 5、10、15 这 3 个数都都可以分解成 n * 5 ,也就是说对于每一个数都能找到一个 2 与之相乘,并且乘积结果为 n * 5 * 2 。因此 15! 阶乘末尾 0 的个数为 3 个。

需要注意的是某些数可以产生多个 5 ,比如 25 有 2 个 5 ,50 也有 2 个 5 。下面我们通过表格来观察一下规律。

510152025
3035404550
5560657075
80859095100
105110115120125
130135140145150

可以观察到对于前 4 列来说,都只能分解出 1 个 5,但是第 5 列却能分解出多个 5。

255 * 5 * 1
505 * 5 * 2
755 * 5 * 3
1005 * 5 * 4
1255 * 5 * 5
1505 * 5 * 6

也就是说 20! 中值为 5 的倍数的个数为 20 / 5 ,但是 25! 中值为 5 的倍数的个数为 25 / 5 再加上 25 多的那个 5。本题规律的关键在于第 5 列,对于 n 的阶乘来说有几个数能列入上面表格中只需要计算 n / 5 再向下取整即可。但是第 5 列是多了 * 个 5 的。可以发现 25、50、75、100、125、150 这些数被计数过 1 次以后,就可以将这个数中的 5 去了。那么结果将变为如下表格

255 * 5 * 15 * 1
505 * 5 * 25 * 2
755 * 5 * 35 * 3
1005 * 5 * 45 * 4
1255 * 5 * 55 * 5
1505 * 5 * 65 * 6

可以发现这刚好又变成了最初表格的 5、10、15、20、25、30。我们只要一直计算 n / 5n / 5 / 5n / 5 / 5 / 5 直到其结果小于 5,并将结果累加即可。

迭代:

const trailingZeroes = n => {
  let total = 0;
  while (n >= 5) {
    n = Math.floor(n / 5);
    total += n;
  }
  return total;
};

递归:

'use strict';
const trailingZeroes = n => {
  const helper = (n, total) => {
    if (n < 5) {
      return total;
    }
    const count = Math.floor(n / 5);
    return helper(count, total + count);
  };
  return helper(n, 0);
};
impl Solution {
    pub fn trailing_zeroes(n: i32) -> i32 {
        fn helper(n: i32, total: i32) -> i32 {
            if n < 5 {
                total
            } else {
                let count = n / 5;
                helper(count, total + count)
            }
        }
        helper(n, 0)
    }
}