阶乘后的零(2022-3-25)每日一练(阶乘的终极解决方案)

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;
}

平方差解法参考的是嘻嘻哈哈学习

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值