描述
给定一个非负整数 n ,返回 n! 结果的末尾为 0 的数量。
n! 是指自然数 n! 的阶乘,即 : N!=1×2×3…(N−2)×(N−1)×NN!=1×2×3…(N−2)×(N−1)×N。
特殊的, 0 的阶乘是 1 。
数据范围: 0<n≤10140<n≤1014
进阶:空间复杂度 O(1)O(1),时间复杂度 O(logn)O(logn)
复杂度要求:
不大于 O(logn)O(logn)
示例1
输入:
3
返回值:
0
说明:
3!=6
示例2
输入:
5
返回值:
1
说明:
5!=120
示例3
输入:
1000000000
返回值:
249999998
思路
- 题目要求计算阶乘末尾0的数量,最直接的方法就是通过计算n!,得出其值,然后在逐个的找出末尾的0,得出末尾0的数量;
- 考虑到N的范围比较大,使用long会溢出,所以采用Java中BigDecimal来进行阶乘的运算;
- 得出阶乘的结果后,再将数值转换成字符串,从尾部开始遍历,找出末尾所有的零。
代码
import java.math.BigDecimal;
public class Solution {
/**
* the number of 0
* @param n long长整型 the number
* @return long长整型
*/
public long thenumberof0 (long n) {
// 使用BigDecimal来存储乘积
BigDecimal multi = new BigDecimal(String.valueOf(1));
// 实现阶乘运算
while(n > 1){
BigDecimal bb = new BigDecimal(String.valueOf(n));
multi = multi.multiply(bb);
--n;
}
// 找出末尾零的的个数
int count = 0;
String str = String.valueOf(multi);
for (int i = str.length()-1;i >= 0;--i){
if (str.charAt(i) != '0'){
break;
}
++count;
}
return count;
}
}
方法二
思路
- 由于N的范围比较大,所以采用方法一可能会导致程序运行超时,无法啊完美解决问题,需要考虑降低时间复杂度,从而提高程序运行速度;
- 观察10以内的数字的互乘,可以发现只有2 * 5 = 10会产生0,也就是说两个数相乘会产生0,则这两个数中必有因子5和2,且5的个数一定是小于2的个数的,所以要找出一个阶乘n!末尾0的数量,只需要找出从1~n这n个数中总共有多少个因子5;
- 但是,从1遍历到n每个数看一下它能除多少次5是不行的。因为n的数据范围是1e18,遍历1e18个数运行时间过大。
- 其实存在如下公式:5的数量count = n/5+n/25+……+n/5
+……;
- 那么这公式是什么意思呢?n/5即阶乘中所有至少含有一个因子5的个数,而n/25即阶乘中所有至少含有两个因子5的个数,由于在n/5中已经统计一次n/25了,所以只需要在加一次n/25即可,以此类推,从而得出n的阶乘中因子5的个数。
- 故可以依据此公式进行计算末尾0的数量。
- 代码
import java.math.BigDecimal;
public class Solution {
/**
* the number of 0
* @param n long长整型 the number
* @return long长整型
*/
public long thenumberof0 (long n) {
long count = 0;
long base = 5;
while(n >= base){
count = count + n / base;
base *= 5;
}
return count;
}
}