172. 阶乘后的零
首先,两个数相乘结果末尾有 0,一定是因为两个数中有因子 2 和 5,因为 10 = 2 x 5。
所以,问题可以转化成阶乘中总共有多少因子2和5。进一步,我们发现,因子2总是比5个数多,因为每个偶数都有因子2,而只有5的倍数才包含因子5,所以问题可以进一步转化为找因子5的个数
以25!
为例,5,10,15,20,25都是5的倍数,但是需要注意25中包含了两个5,所以总共有1+1+1+1+2=6个因子5。
进一步延伸,以125!
为例,首先找到5,10,...,120,125
总共125/5=25个因子5;而进一步的,我们还可以找到25,50,...,100,125
共125/25=5个因子5,还可以找到125/125=1个因子5,所以总共有125!
中总共有25+5+1=31个因子5,也就是说阶乘末尾有31个0。
下面是代码:
class Solution {
public int trailingZeroes(int n) {
int res = 0;
int f = 5;//5的倍数factor
while(n >= f) {
res += n / f;
f *= 5;
}
return res;
}
}
这样,这道题就解决了,时间复杂度是底数为 5 的对数,也就是 O(logN)
,我们看看下如何基于这道题的解法完成下一道题目。
793. 阶乘函数后 K 个零
首先我们可以知道阶乘后0的个数随n!增大而增加,而n!随n的增大而增加,针对这种单调函数找区间的问题,显然我们可以使用二分查找的方法。
那么二分查找的区间下界可以取0,问题的关键在于如何确定区间上界,理论上应该是取正无穷,但是数学上的正无穷不可能在代码中表示出来。所以,进一步观察题目和测试数据,K的取值范围为0 <= k <= 10^9
,那么我们只要找到一个数x,是的x! 后0的个数大于k即可,我们刚好可以通过172题的方法去找这个数。
首先我们可以测试一下Integer.MAX_VALUE = 2^31 - 1
,发现INT_MAX后总共有536,870,902 < 10^9,所以需要尝试更大的数比如Long.MAX_VALUE = 2^63 - 1
,发现满足条件。下一步我们使用二分查找方法即可。
class Solution {
long trailingZeroes(long n) {
long res = 0;
for (long d = n; d / 5 > 0; d = d / 5) {
res += d / 5;
}
//System.out.println(res);
return res;
}
public int preimageSizeFZF(int k) {
return (int)(right_bound(k) - left_bound(k) + 1);
}
long left_bound(int target){
long lo = 0, hi = Long.MAX_VALUE;
while(lo <= hi) {
long mid = lo + (hi - lo) / 2;
long tra = trailingZeroes(mid);
if(tra > target) {
hi = mid - 1;
}else if(tra == target) {
hi = mid - 1;
}else if(tra < target) {
lo = mid + 1;
}
}
return hi + 1;
}
long right_bound(int target) {
long lo = 0, hi = Long.MAX_VALUE;
while (lo <= hi) {
long mid = lo + (hi - lo) / 2;
if (trailingZeroes(mid) < target) {
lo = mid + 1;
} else if (trailingZeroes(mid) > target) {
hi = mid - 1;
} else {
lo = mid + 1;
}
}
return lo - 1;
}
}