对于阶乘的题目,尽量不要去想真正算出来,因为实在是太大了
leet172.阶乘后的0
class Solution {
public int trailingZeroes(int n) {
long res=0;
long devisor=5;
while(devisor<=n){
res=res+n/devisor;
devisor=5*devisor;
}
return (int)res;
}
}
结果的末尾的 0 从哪里来的,两个数相乘结果末尾有 0,一定是因为两个数中有因子 2 和 5,因为 10 = 2 x 5。也就是说,问题转化为:n!
最多可以分解出多少个因子 2 和 5?比如说n = 25
,那么25!
最多可以分解出几个 2 和 5 相乘?这个主要取决于能分解出几个因子 5,因为每个偶数都能分解出因子 2,因子 2 肯定比因子 5 多得多。现在,问题转化为:n!
最多可以分解出多少个因子 5?
难点在于像 25,50,125 这样的数,可以提供不止一个因子 5,怎么才能不漏掉呢?我们假设n = 125
,来算一算125!
的结果末尾有几个 0:首先,125 / 5 = 25,这一步就是计算有多少个像 5,15,20,25 这些 5 的倍数,它们一定可以提供一个因子 5。像 25,50,75 这些 25 的倍数,可以提供两个因子 5,那么我们再计算出125!
中有 125 / 25 = 5 个 25 的倍数,它们每人可以额外再提供一个因子 5。我们发现 125 = 5 x 5 x 5,像 125,250 这些 125 的倍数,可以提供 3 个因子 5,那么我们还得再计算出125!
中有 125 / 125 = 1 个 125 的倍数,它还可以额外再提供一个因子 5。
leet793.
现在是给你一个非负整数K
,问你有多少个n
,使得n!
结果末尾有K
个 0。
最粗暴的想法是从0开始输入上述函数,当返回的结果等于k时统计个数。但很明显这样复杂度太高,所以想到用二分法剪枝。
其实这里用的就是二分法处理单调函数,明显随着输入函数的数变大,结果单调不减。
结果其实就是分别找结果等于k的结果的左边界与右边界。
输入为low=0,high为long的最大值。
用二分法得到两个结果。
class Solution {
public int preimageSizeFZF(int K) {
return (int)(rightbound(K)-leftbound(K)+1);
}
private long leftbound(int K){
long high=Long.MAX_VALUE;
long low=0;
while(low<high){
long mid=low+(high-low)/2;
if(numberofzero(mid)>K){high=mid;}
else if(numberofzero(mid)<K){low=mid+1;}
else if(numberofzero(mid)==K){high=mid;}
}
return low;
}
private long rightbound(int K){
long high=Long.MAX_VALUE;
long low=0;
while(low<high){
long mid=low+(high-low)/2;
if(numberofzero(mid)>K){high=mid;}
else if(numberofzero(mid)<K){low=mid+1;}
else if(numberofzero(mid)==K){low=mid+1;}
}
return low-1;
}
private long numberofzero(long n){
long res=0;
long devisor=5;
while(devisor<=n){
res=res+n/devisor;
devisor=5*devisor;
}
return res;
}
}