Leetcode 793:阶乘函数后K个零(超详细的解法!!!)

f(x)x! 末尾是0的数量。(回想一下 x! = 1 * 2 * 3 * ... * x,且0! = 1

例如, f(3) = 0 ,因为3! = 6的末尾没有0;而 f(11) = 2 ,因为11!= 39916800末端有20。给定 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(K1)。使用二分法的话,我们还需要确定左右边界,显然左边界就是0,而右边界采用偷懒的方式就是2**63-1,实际上右边界不可能大于5*(K+1)(因为K!至少包含K/50)。

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)这个区间内的阶乘有00[5,2*5)这个区间内的阶乘有10。。。类推下去

[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的个数相同。也就是说如果K0结尾的数存在,那么一定同时存在5个,否则有0个。那么这个问题简化为判断哪些数的阶乘数结尾是00,哪些数是50。我们可以将数 x ! x! x!写成 5 5 5进制形式:

  • x ! = 5 n a n + 5 n − 1 a n − 1 + . . . + 5 0 a 0 x!=5^na_n+5^{n-1}a_{n-1}+...+5^0a_0 x!=5nan+5n1an1+...+50a0

那么 f ( x ) f(x) f(x)(表示计算 x x x的阶乘函数)可以表示为

  • f ( x ) = ∑ i = 1 n ⌊ x 5 i ⌋ = a 1 ∗ 1 + a 2 ∗ ( 1 + 5 ) + . . . + a n ∗ ∑ i = 0 n − 1 5 i f(x)=\sum_{i=1}^n \lfloor \frac{x}{5^i}\rfloor=a_1*1+a_2*(1+5)+...+a_n*\sum_{i=0}^{n-1}5^i f(x)=i=1n5ix=a11+a2(1+5)+...+ani=0n15i

现在的问题就变成了 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

如有问题,希望大家指出!!!

你可能感兴趣的:(leetcode解题指南,Problems)