172. 阶乘后的零(2022-3-25)
给定一个整数 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 <= 10^4
解题思路
这道题不可以关注求出阶乘,再求0的个数(因为一定会溢出),尝试使用数学思维,去寻找规律。
寻找0的个数实际上是寻找10的个数,也就是2*5
的个数,而他们依赖于5的个数(因为5一定比2少),所以我们实际上是去找5的个数。
👌 这个问题的求解方向已经变为,寻找质因子5的个数;假设我们现在求11!
的5的个数,很容易得出其中有2个5;那么55!
的5的个数呢?实际上是11 + 2个,[1,55]
中5的个数应为11个,求完一波5后还剩11,还得再求一波,那么[1,11]
中5的个数为2个,[1,2]
中没有5了所以总数为11 + 2。
上边是我投机取巧的理解,具体严谨的证明和解释,请参考官方的题解,我认为非常详尽!
var trailingZeroes = function(n) {
let ret = 0
while(n >= 5){
n = n / 5 | 0
ret += n
}
return ret
// 递归调用
// return n >= 5 ? (n / 5 | 0 ) + trailingZeroes(n / 5 | 0) : 0
};
OK,既然看到了阶乘的题,自然就在脑海里思考了一下求阶乘的方法,除了朴素模拟之外,好像没有其他解法了。很不甘心,所以去寻找一番。结果如下:
- 大部分都是递归求解,直接递归或者尾递归。
- for、while等循环模拟求解,(这都不是我想要的)
- 通过平方差(唯一一个我想要的,时间复杂度O(n/2))
// 普通递归
var factorial = function (n) {
return n > 1 ? n * facorial(n-1) : 1
}
// 尾递归 指的是它的返回值不属于表达式的一部分,且递归调用在函数体的最后
// 最终结果将会通过参数返回
var factorial = function (n, total) {
if (n < 2) return total
return factorial(n-1, total * n)
}
// for while 加上记忆优化
var factorial = function (n) {
let a = 1// a指的是(i-1)! i!= i * (i-1)! = i * (i-1) * (i-2)!
for(let i = 2; i <= n; i++){
a = i * a
}
return a
}
// 平方差 具体解释可以看原博客,大佬写的很明白了
var factorial = function(n){
if(n <= 1) return 1;
const middle = Math.ceil(n / 2); //取中间值
let tmp = middle * middle
,result = n & 1 == 1 ? middle : middle * n; //奇偶数的基础乘数规律不同
for(let i = 1 ; i <= n - 2 ; i += 2){ //连续减奇数得出各项乘数
tmp -= i;
result = BigInt(result) * BigInt(tmp);
}
return result;
}
平方差解法参考的是嘻嘻哈哈学习