题目简介:
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 的数量。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/preimage-size-of-factorial-zeroes-function
运用数学思想+二分查找。
首先一开始我就直接想去计算每个数的阶乘的值并判断其末尾有多个零,再就是想要用双层for循环去将其逐个遍历,现在想想这种方法实在是不可行。
接下来我开始深入思考:
末尾为零简单就是需要一个末尾为5的数与一个偶数相乘可得,以及10的倍数。再找到它们的共同点就是它们的因子有5的存在,我们可以抽茧剥丝的发现只要找到有多少个因子5阶乘的末尾就有多少个零。那么再仔细思考一下这道题是需要找出满足末尾为k个零的非负整数的数量x,因此我们可以发现从5到10到15再到20这其中每五个数为一组,但到了25时,我们发现它一下子就从末尾零的个数4到6,这是因为25的因子5有两个。那么我们就可以发现最终的答案要么是0,要么是5,我们只要找到是否有那么多个因子等于k的值,等于答案即为5,不等于为0。
二分法的使用需要时一个有序的排列,符合本题的要求,通过一系列数学公式进行缩放可以等到范围为【4k,5k】,因此我们只需要判断如k=1时判读4和5就行。
class Solution {
public int preimageSizeFZF(int k) {
if (k <= 1) return 5;
return f(k) - f(k - 1);
}
int f(int x) {
long l = 0, r = (long) 1e10;
while (l < r) {
long mid = l + r + 1 >> 1;
if (getCnt(mid) <= x)
l = mid;
else r = mid - 1;
}
return (int)r;
}
long getCnt(long x) {
long ans = 0;
while (x != 0) {
ans += x / 5; x /= 5;
}
return ans;
}
}