携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天,点击查看活动详情
题目描述
f(x) 是 x! 末尾是 0 的数量。回想一下 x! = 1 * 2 * 3 * ... * x,且 0! = 1 。
- 例如, f(3) = 0 ,因为 3! = 6 的末尾没有 0 ;而 f(11) = 2 ,因为 11!= 39916800 末端有 2 个 0 。
给定 k,找出返回能满足 f(x) = k 的非负整数 x 的数量。
示例 1:
输入:k = 0
输出:5
解释:0!, 1!, 2!, 3!, 和 4! 均符合 k = 0 的条件。
示例 2:
输入:k = 5
输出:0
解释:没有匹配到这样的 x!,符合 k = 5 的条件。
示例 3:
输入: k = 3
输出: 5
提示:
- 0 <= k <= 109
思路
要想解出本题,首先得解出一个子问题:如何求解某个数阶乘后的后导0个数。我们知道,1个0就是1个2乘以1个5。而对于阶乘来说,2一定比5多,所以这里后导0的个数就是分解质因数后5的个数。这个可以使用辗转相除的犯法来快速求出,这个不做过多介绍。
有个这个快速求出后导0个数的方法后,我们再定义一个函数get793(x)表示某个数阶乘后,后导0小于等于x的数字的数量。由于阶乘是随着x的增加而不断增大的,而且阶乘的增大是后一个阶乘结果必然包含前面一个阶乘结果的所有质因数,相当于是完成包含,所以函数get793(x)随着x的增大,值也是单调增大的。既然这个函数有单调性,那我们就可以通过二分法来求值,最后,get793(k) - get793(k-1)就是题目要求的答案。
当然,这里还有1个注意点是,k=0的情况,因为函数get793(-1)是没有意义的,这种情况需要先独立排除掉。
Java版本代码
class Solution {
public int preimageSizeFZF(int k) {
if (k == 0) {
return 5;
}
return get793(k) - get793(k-1);
}
private int get793(int x) {
long l = 0, r = (long) 1e10;
while (l < r) {
long mid = l + r + 1 >> 1;
if (get5Nums(mid) <= x) {
l = mid;
} else {
r = mid - 1;
}
}
return (int)l;
}
/**
* 获取x!分解质因数后5的个数
* @param x
* @return
*/
private int get5Nums(long x) {
int ans = 0;
while (x > 0) {
ans += x / 5;
x /= 5;
}
return ans;
}
}