LeetCode 172. 阶乘后的零:从暴力到最优,拆解解题核心

刷LeetCode时,遇到「阶乘后的零」这道题,初看简单,实则藏着优化的小技巧。今天就从题目本身出发,一步步拆解两种解题思路,对比暴力解法和最优解法的差异,帮大家吃透这道经典题目,也掌握一类数学问题的解题逻辑。

一、题目解读:读懂「尾随零」的本质

题目很简单:给定一个整数n,返回n!(n的阶乘)结果中尾随零的数量。提示里明确了n! = n × (n-1) × (n-2) × ... × 3 × 2 × 1。

这里有个关键误区:很多人会以为尾随零的数量是由阶乘中10的个数决定的------确实没错,但10是2×5的乘积,而阶乘中2的数量永远比5多(比如每两个数就有一个是2的倍数,每五个数才有一个是5的倍数)。所以,尾随零的数量,本质上是阶乘中质因数5的个数

搞懂这一点,解题就成功了一半。接下来我们看两种解法,从基础到进阶。

二、解法一:暴力枚举,逐个统计5的个数

最直观的思路:遍历从1到n的每一个数,统计每个数中包含的质因数5的个数,最后累加总和,就是尾随零的数量。

对应代码如下(TypeScript):

typescript 复制代码
function trailingZeroes_1(n: number): number {
  let ans = 0;
  for (let i = 1; i <= n; i++) {
    let temp = 0;
    let j = i;
    while (j % 5 === 0) {
      temp++;
      j = Math.floor(j / 5);
    }
    ans += temp;
  }
  return ans;
};

代码拆解

  • 外层for循环:遍历1到n的每一个数i,逐个分析每个数包含的5的个数。

  • 内层while循环:对于当前数i(用j临时存储,避免修改i),判断是否能被5整除;如果能,就计数temp加1,同时将j除以5(继续判断是否有多个5,比如25=5×5,需要统计2个5)。

  • ans累加:将每个数的temp(5的个数)累加到结果中,最终返回ans。

优缺点分析

优点:逻辑简单,容易理解,适合新手入门,能快速想到这种思路。

缺点:效率较低。当n很大时(比如n=10^5),for循环要执行n次,每个数又可能执行多次while循环,时间复杂度是O(n×log₅n),会出现超时情况。

三、解法二:数学优化,直接计算5的总个数

既然暴力解法效率不高,我们就需要优化思路。结合前面的核心结论------尾随零的数量=质因数5的个数,我们可以用数学公式直接计算,无需逐个遍历。

核心逻辑:

  • n/5:计算1到n中,至少包含1个5的数的个数(比如n=25,有5、10、15、20、25,共5个,25/5=5)。

  • n/25:计算1到n中,至少包含2个5的数的个数(比如25,包含2个5,25/25=1;50包含2个5,以此类推)------这些数在n/5中已经被统计过1次,这里需要再额外统计1次。

  • n/125:计算1到n中,至少包含3个5的数的个数(比如125,包含3个5),同样需要额外统计1次。

  • 以此类推,直到n除以5的某次幂结果为0,停止计算,累加所有结果,就是质因数5的总个数。

对应代码如下(TypeScript):

typescript 复制代码
/**
 * n/5 = 有多少个数 至少含 1 个 5
 * n/25 = 有多少个数 额外多 1 个 5(25=5×5)
 * n/125 = 有多少个数 再额外多 1 个 5(125=5×5×5)
 * 以此类推......
 * @param n 
 * @returns 
 */
function trailingZeroes_2(n: number): number {
  let ans = 0;
  while (n !== 0) {
    n = Math.floor(n / 5);
    ans += n;
  }
  return ans;
};

代码拆解

  • while循环:每次将n除以5(向下取整),得到当前层级(51、52、5^3...)中包含5的数的个数。

  • ans累加:将每次除以5的结果累加到ans中,直到n变为0(此时再除以5结果为0,无需继续统计)。

举个例子:n=25

  • 第一次循环:n=25→Math.floor(25/5)=5,ans=5(统计5、10、15、20、25各1个5)。

  • 第二次循环:n=5→Math.floor(5/5)=1,ans=5+1=6(统计25额外的1个5)。

  • 第三次循环:n=1→Math.floor(1/5)=0,循环结束,返回6。

验证:25!的尾随零数量确实是6,和代码计算结果一致。

优缺点分析

优点:效率极高,时间复杂度是O(log₅n),即使n=109,循环也只需要执行不到10次(510=9765625,5^13=1220703125),完全不会超时。

缺点:逻辑需要稍微转个弯,需要理解「多次除以5」的本质,新手可能需要多琢磨一下。

四、两种解法对比&总结

解法 时间复杂度 空间复杂度 核心思路 适用场景
暴力枚举(trailingZeroes_1) O(n×log₅n) O(1) 逐个统计每个数的质因数5个数 n较小,新手理解思路
数学优化(trailingZeroes_2) O(log₅n) O(1) 累加n/5、n/25、n/125...的结果 n较大,追求高效解题

五、解题关键&拓展思考

解题关键

  1. 抓住核心:尾随零的数量由质因数5的个数决定,而非10的个数(因为2的数量足够多)。

  2. 优化思路:避免逐个遍历,利用数学规律,直接计算不同层级(51、52...)中5的个数,大幅提升效率。

拓展思考

这道题的本质是「质因数分解」的应用,类似的题目还有「统计阶乘中某个质因数的个数」,解题思路可以复用:统计n/k + n/k² + n/k³ + ... 直到结果为0。

比如,如果题目问n!中质因数2的个数,思路完全一样,只是把5换成2即可------但注意,此时2的数量会比5多,所以如果是求尾随零,还是要统计5的个数哦。

六、总结

LeetCode 172这道题,看似简单,却能很好地考察我们「从暴力到优化」的解题思维。新手可以先写暴力解法,理解核心逻辑;再琢磨数学优化思路,掌握高效解题的技巧。

相关推荐
SEO_juper9 分钟前
新独立站冷启动收录全攻略:配置、推送、抓取配额优化完整手册
前端·谷歌·seo·跨境电商·外贸·geo·独立站
TinssonTai13 分钟前
这个 VS Code 插件让我的 AI Coding 又快又稳 - 旧瓶装新酒
前端·人工智能·程序员
体验家14 分钟前
体验家 XMPlus 网页端问卷 SDK 技术解析:用几行 JavaScript 实现精准场景触发与防打扰机制
开发语言·前端·javascript
code_pgf15 分钟前
改进模型架构来减少MLLMs中的幻觉现象
人工智能·深度学习·算法
VidDown19 分钟前
VidDown 工具站:视频分辨率技术
javascript·网络·编辑器·音视频·视频编解码·视频
2301_7644413322 分钟前
基于AI的本地文件归档智能管理工具梳理
人工智能·python·算法·目标检测·交互
二十七剑24 分钟前
LangGraph 源码深度解析:Node 节点 Protocol 与 StateNodeSpec 核心机制
开发语言·python
AC赳赳老秦26 分钟前
OpenClaw + 云数据库运维:自动备份、扩容、迁移 RDS/MySQL 云数据库
运维·开发语言·数据库·人工智能·python·mysql·openclaw
醉城夜风~26 分钟前
类和对象III
开发语言·c++
冷小鱼28 分钟前
高级研发编码习惯:从规范到艺术,再到AI+时代的人机协同
java·开发语言·python·编码习惯