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
,找出多少个非负整数x
,有 f(x) = K
的性质。
示例 1:
输入:K = 0
输出:5
解释: 0!, 1!, 2!, 3!, and 4! 均符合 K = 0 的条件。
示例 2:
输入:K = 5
输出:0
解释:没有匹配到这样的 x!,符合K = 5 的条件。
注意:
K
是范围在 [0, 10^9]
的整数。解题思路
首先你一定可以想到暴力解法,但是数据量太大了,暴力解法显然会超时。那么怎么办?查找问题首先不难想到二分法,二分法最重要的就是判定函数怎么写。仔细思考不难发现,0
只可以通过5x2
得到,那么我们只要判断给定的数x
有几个5
即可(因为对应2
的数量一定可以满足)。
def check(x):
return 0 if x < 5 else check(x//5) + x//5
接下来我们需要通过二分法找到满足条件的最大值是谁,假设为 f ( K ) f(K) f(K),那么最后的个数就是 f ( K ) − f ( K − 1 ) f(K)-f(K-1) f(K)−f(K−1)。使用二分法的话,我们还需要确定左右边界,显然左边界就是0
,而右边界采用偷懒的方式就是2**63-1
,实际上右边界不可能大于5*(K+1)
(因为K!
至少包含K/5
个0
)。
class Solution:
def preimageSizeFZF(self, K: 'int') -> 'int':
def check(x):
return 0 if x < 5 else check(x//5) + x//5
def bs(x):
l, r = 0, 5*(x + 1)
while l < r:
mid = (l + r) >> 1
if check(mid) <= x:
l = mid + 1
else:
r = mid
if check(l) == x:
return l
return l - 1
return bs(K) - bs(K-1)
这个问题实际上可以通过数学解,我们知道[0,4)
这个区间内的阶乘有0
个0
,[5,2*5)
这个区间内的阶乘有1
个0
。。。类推下去
[0,5) 0
[5,2*5) 1
[2*5,3*5) 2
[3*5,4*5) 3
[4*5,5*5) 4
[5*5,6*5) 6
通过上面的例子,我们知道区间 [ n 5 m , ( n + 1 ) 5 m ] [n5^m,(n+1)5^m] [n5m,(n+1)5m]区间内的数,其阶乘数最后0
的个数相同。也就是说如果K
个0
结尾的数存在,那么一定同时存在5
个,否则有0
个。那么这个问题简化为判断哪些数的阶乘数结尾是0
个0
,哪些数是5
个0
。我们可以将数 x ! x! x!写成 5 5 5进制形式:
那么 f ( x ) f(x) f(x)(表示计算 x x x的阶乘函数)可以表示为
现在的问题就变成了 K K K能否表示为上面这个式子,也就是判断对应 a i a_i ai的值是不是为 5 5 5即可。
class Solution:
def preimageSizeFZF(self, K: 'int') -> 'int':
x = 1
while x < K:
x = x * 5 + 1
while K:
x = (x - 1)//5
if K // x == 5:
return 0
K %= x
return 5
reference:
https://leetcode.com/problems/preimage-size-of-factorial-zeroes-function/discuss/117821/Four-binary-search-solutions-based-on-different-ideas
https://leetcode-cn.com/problems/preimage-size-of-factorial-zeroes-function/solution/shu-xue-tui-dao-by-jriver/
https://leetcode-cn.com/problems/preimage-size-of-factorial-zeroes-function/solution/kuai-su-cha-zhao-zui-ke-neng-de-jie-guo-by-xinzhao/
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!