172. 阶乘后的零
给定一个整数 n,返回 n! 结果尾数中零的数量。
示例 1:
输入: 3
输出: 0
解释: 3! = 6, 尾数中没有零。
示例 2:
输入: 5
输出: 1
解释: 5! = 120, 尾数中有 1 个零.
说明: 你算法的时间复杂度应为 O(log n) 。
解题思路
方法一: 暴力算法
直接求结果, 然后数出结果有多少个0。
public int trailingZeroes(int n) {
int factorial = 1;
for (int i = 1; i <= n; i++) {
factorial *= i;
}
return zeroesCount(factorial);
}
public int zeroesCount(int x) {
int zeroCount = 0;
while (x % 10 == 0) {
zeroCount++;
x /= 10;
}
return zeroCount;
}
方法二: 暴力找因子5出现的次数
首先要知道一点, 某个数里尾数0是如果来的。10, 40, 100, 120等等。尾数的0, 一定是由他的因子2和因子5相乘得到。
所以问题转化为1, 2, 3 ... N这N个数字里, 因子2出现了多少次, 因子5出现了多少次。取这两个次数的较小者就是尾数0的个数。
再思考的话, 又可以发现个一个规律。因子2出现次数和因子5出现次数的较小者一定是因子5出现的次数。因为在1,2,3 ... N这N个数字里, 因子2, 每2个数字就会出现, 而因子5, 每5个数字才会出现。所以因子2的个数, 远大于因子5的个数。所以最终的问题转化为求因子5出现的个数。
public int trailingZeroes(int n) {
int count = 0;
// 遍历1,2,3...N
for (int i = 1; i <= n; i++) {
int N = i;
// 找当前数字i, 因子5出现的次数
while (N > 0) {
if (N % 5 == 0) {
count++;
N /= 5;
} else {
break;
}
}
}
return count;
}
方法三: 找因子5出现次数
比方法二还有一个更好的方法去求5出现的次数。
方法二说到了5是每5个出现一次, 在[1...N]上, 会出现5的数字是5, 10, 15, 20, 25, 30, 35, 40, 45, 50 ...... 250, 255....等。在这一轮计算里, 出现了数字有n / 5
个。
这样是不够的, 这其中还有25, 50, 100....。这些数字5因子都是出现了2次的。所以这些数字还要再加上一次。也就是n / 25
次。
与上面同样的道理, 这里还有125, 250, 375, 500..., 这些因子里数字5因子是出现了3次的。所以这些数字还要再加上一次, 也就是n / 125
次。
所以实际结果就是n/5 + n/25 + n/125 + n/625 + .....
public int trailingZeroes(int n) {
int count = 0;
while (n > 0) {
count += n / 5;
n = n / 5;
}
return count;
}