欢迎光临
我们一直在努力

D.二分查找-二分答案-第K小/第K大——793. 阶乘函数后 K 个零

题目链接:793. 阶乘函数后 K 个零(困难)

算法原理:

解法:二分查找

0ms击败100.00%

时间复杂度O((logk)²)

①目标变量:非负整数x

②目标条件:求出末尾是0的数=k的非负整数 x 的数量

③转换逻辑:当前非负整数mid的0是否≥k

具体步骤

①确定边界

left:0

right:5L×k,答案只能是0或5,因此最安全的边界是5×k,而L是代表long类型

②确定二分模型:x ↑ 0的数量 ↑ 呈正相关单调,而我们只需找到第一个0的数量=k的非负整数x即可确定有没有这个数,有的话,必然是5个,否则就是0个,具体见下面分析

③check方法设计:此处check返回值与以往不同,因为我们要确定0的的数量=k的非负整数x是否存在,因此我们就算返回boolean也要在主方法中再判断一次,为了代码简洁,就直接返回当前数mid的后面0的数量

那么如何计算出来呢?通过观察可以发现,要想后面出现0,那么这个数必然是10的倍数,那么我们只需统计出当前数里面有多少个10就行吗?不是的,举个反例:10!=3628800,这里就有两个0,但只进行了一次×10操作,那这是为什么呢?其实是里面有2和5又配出了一个10,换言之,我们只要统计出2和5配对的数量即可,又由于阶乘的过程中,因数2远远大于因数5的数量,因此我们最终仅需统计出当前数里面有多少个5即可

这也就导致满足k值的要么是5个要么是0个,因为当25满足时,26、27、28、29也同样满足,但30就不行了,如果不满足,那么就是一个都没有

关键易错点复盘

1.阶乘末尾 0 的个数计算错误 错误写法:mid/5 原因:这个结果是[1,mid]有多少个5的倍数,而非有多少个5

比如当mid=25时,这个结果表示的是5、10、15、20、25

但实际上是5=1×5、10=2×5、15=3×5、20=4×5、25=5×5,一共6个5,而非5个

因此需要用while循环来求出“每个5的倍数中有多少个因数5,再累加”

2.审题错误

题目问的是“满足末尾是0的数=k的非负整数 x 的数量”而非“满足末尾是0的数=k的非负整数 x”

这也就是为什么这次的check方法返回值要改变成int反而更简洁的原因

3.边界设置不当

left:有的伙伴会把left直接设置成5,这样直接忽略了x=0~4的情况

right:右边界不够大,由于题目中k可达1e9,因此需要的x约为4e9,这时需要初始化为5L×k,因为f(5k)一定≥k

Java代码:

class Solution {
public int preimageSizeFZF(int k) {
long left=0,right=5L*k;
while(left<right){
long mid=left+(right-left)/2;
if(check(mid)<k) left=mid+1;
else right=mid;
}
return check(left)==k?5:0;
}
private int check(long mid){
int cnt=0;
while(mid>0){
mid/=5;
cnt+=mid;
}
return cnt;
}
}

赞(0)
未经允许不得转载:171主机测评 » D.二分查找-二分答案-第K小/第K大——793. 阶乘函数后 K 个零
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址