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的个数最后累加总和就是尾随零的数量。对应代码如下TypeScriptfunctiontrailingZeroes_1(n:number):number{letans0;for(leti1;in;i){lettemp0;letji;while(j%50){temp;jMath.floor(j/5);}anstemp;}returnans;};代码拆解外层for循环遍历1到n的每一个数i逐个分析每个数包含的5的个数。内层while循环对于当前数i用j临时存储避免修改i判断是否能被5整除如果能就计数temp加1同时将j除以5继续判断是否有多个5比如255×5需要统计2个5。ans累加将每个数的temp5的个数累加到结果中最终返回ans。优缺点分析优点逻辑简单容易理解适合新手入门能快速想到这种思路。缺点效率较低。当n很大时比如n10^5for循环要执行n次每个数又可能执行多次while循环时间复杂度是O(n×log₅n)会出现超时情况。三、解法二数学优化直接计算5的总个数既然暴力解法效率不高我们就需要优化思路。结合前面的核心结论——尾随零的数量质因数5的个数我们可以用数学公式直接计算无需逐个遍历。核心逻辑n/5计算1到n中至少包含1个5的数的个数比如n25有5、10、15、20、25共5个25/55。n/25计算1到n中至少包含2个5的数的个数比如25包含2个525/25150包含2个5以此类推——这些数在n/5中已经被统计过1次这里需要再额外统计1次。n/125计算1到n中至少包含3个5的数的个数比如125包含3个5同样需要额外统计1次。以此类推直到n除以5的某次幂结果为0停止计算累加所有结果就是质因数5的总个数。对应代码如下TypeScript/** * n/5 有多少个数 至少含 1 个 5 * n/25 有多少个数 额外多 1 个 5255×5 * n/125 有多少个数 再额外多 1 个 51255×5×5 * 以此类推…… * param n * returns */functiontrailingZeroes_2(n:number):number{letans0;while(n!0){nMath.floor(n/5);ansn;}returnans;};代码拆解while循环每次将n除以5向下取整得到当前层级51、52、5^3…中包含5的数的个数。ans累加将每次除以5的结果累加到ans中直到n变为0此时再除以5结果为0无需继续统计。举个例子n25第一次循环n25→Math.floor(25/5)5ans5统计5、10、15、20、25各1个5。第二次循环n5→Math.floor(5/5)1ans516统计25额外的1个5。第三次循环n1→Math.floor(1/5)0循环结束返回6。验证25!的尾随零数量确实是6和代码计算结果一致。优缺点分析优点效率极高时间复杂度是O(log₅n)即使n109循环也只需要执行不到10次51097656255^131220703125完全不会超时。缺点逻辑需要稍微转个弯需要理解「多次除以5」的本质新手可能需要多琢磨一下。四、两种解法对比总结解法时间复杂度空间复杂度核心思路适用场景暴力枚举trailingZeroes_1O(n×log₅n)O(1)逐个统计每个数的质因数5个数n较小新手理解思路数学优化trailingZeroes_2O(log₅n)O(1)累加n/5、n/25、n/125…的结果n较大追求高效解题五、解题关键拓展思考解题关键抓住核心尾随零的数量由质因数5的个数决定而非10的个数因为2的数量足够多。优化思路避免逐个遍历利用数学规律直接计算不同层级51、52…中5的个数大幅提升效率。拓展思考这道题的本质是「质因数分解」的应用类似的题目还有「统计阶乘中某个质因数的个数」解题思路可以复用统计n/k n/k² n/k³ … 直到结果为0。比如如果题目问n!中质因数2的个数思路完全一样只是把5换成2即可——但注意此时2的数量会比5多所以如果是求尾随零还是要统计5的个数哦。六、总结LeetCode 172这道题看似简单却能很好地考察我们「从暴力到优化」的解题思维。新手可以先写暴力解法理解核心逻辑再琢磨数学优化思路掌握高效解题的技巧。