Let f(x) be the number of zeroes at the end of x!. (Recall that x! = 1 * 2 * 3 * ... * x, and by convention, 0! = 1.)

For example, f(3) = 0 because 3! = 6 has no zeroes at the end, while f(11) = 2 because 11! = 39916800 has 2 zeroes at the end. Given K, find how many non-negative integers x have the property that f(x) = K.

Example 1:
Input: K = 0
Output: 5
Explanation: 0!, 1!, 2!, 3!, and 4! end with K = 0 zeroes. Example 2:
Input: K = 5
Output: 0
Explanation: There is no x such that x! ends in K = 5 zeroes.

Note:

  • K will be an integer in the range [0, 10^9].

这道题的题目名称非常的难懂,但是读了题目内容以后,就不难理解了,定义函数 f(x) 为 x! 的末尾0的个数,现在给了我们一个非负整数K,问使得 f(x)=K 成立的非负整数的个数。之前做过一道有关阶乘末尾零的个数的题 Factorial Trailing Zeroes,从那道里知道了末尾0其实是由2和5相乘为 10 得到的,而阶乘中2的数量远多于5的个数,所以 10 的个数就只取决于5的个数。需要注意的一点就是,像 25,125,这样的不只含有一个5的数字需要考虑进去。比如,24 的阶乘末尾有4个0,分别是 5,10,15,20 中的四个5组成的,而 25 的阶乘末尾就有6个0,分别是 5,10,15,20 中的各一个5,还有 25 中的两个5,所以共有六个5,那么就不存在其阶乘数末尾有5个0的数。还有一个很重要的规律需要发现,对于 20,21,22,23,24,这五个数的阶乘数末尾零的个数其实是相同的,都是有4个,因为它们包含的5的个数相同。而 19,18,17,16,15,这五个数末尾零个数相同,均为3。那么我们其实可以发现,每五个数,必会至少多出1个5,有可能更多。所以阶乘末尾零个数均为K个的x值,只有两种情况,要么是5,要么是0,这个规律得出来后,继续向着正确的解题方向前进。

基于之前那道题 Factorial Trailing Zeroes 的解法,可以知道如何快速求一个给定的数字阶乘末尾零的个数,那么只要找到了一个这样的数,其阶乘末尾零的个数等于K的话,那么就说明总共有5个这样的数,返回5,反之,如果找不到这样的数字,就返回0。像这种选一个 candidate 数字,再进行验证的操作,用二分搜索法就是极好的,属于博主的总结帖中 LeetCode Binary Search Summary 二分搜索法小结 的第四类,用子函数当作判断关系。首先要确定二分搜索法的范围,左边界很好确定,为0就行了,关键是来确定右边界,来分析一下,一个数字的阶乘末尾零个数为K,那么这个数字能有多大,就拿前面举的例子来说吧,末尾有4个0的最大数字是 24,有六个0的最大是 29,可以发现它们都不会超过 5*(K+1) 这个范围,所以这就是右边界,注意右边界可能会超过整型数范围,要用长整型来表示。那么之后就是经典的二分搜索法的步骤了,确定一个中间值 mid,然后调用子函数来计算 mid 的阶乘数末尾零的个数,用来和K比较大小,如果相等了,直接返回5,如果小于K,那么更新 left 为 mid+1,反之,更新 right 为 mid 即可,最终没找到的话,返回0即可,参见代码如下:

解法一:

class Solution {
public:
int preimageSizeFZF(int K) {
long left = , right = 5L * (K + );
while (left < right) {
long mid = left + (right - left) / ;
long cnt = numOfTrailingZeros(mid);
if (cnt == K) return ;
else if (cnt < K) left = mid + ;
else right = mid;
}
return ;
}
long numOfTrailingZeros(long x) {
long res = ;
for (; x > ; x /= ) {
res += x / ;
}
return res;
}
};

下面这种解法是把子函数融到了 while 循环内,使得看起来更加简洁一些,解题思路跟上面的解法一模一样,参见代码如下:

解法二:

class Solution {
public:
int preimageSizeFZF(int K) {
long left = , right = 5L * (K + );
while (left < right) {
long mid = left + (right - left) / , cnt = ;
for (long i = ; mid / i > ; i *= ) {
cnt += mid / i;
}
if (cnt == K) return ;
else if (cnt < K) left = mid + ;
else right = mid;
}
return ;
}
};

下面这种解法也挺巧妙的,也是根据观察规律推出来的,我们首先来看x为1到 25 的情况:

x:    1 2 3 4  6 7 8 9  11 12 13 14  16 17 18 19  21 22 23 24
f(x): 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4
g(x): 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

这里,f(x) 是表示 x! 末尾零的个数,而 g(x) = f(x) - f(x-1),其实还可以通过观察发现,f(x) = sum(g(x)).

再仔细观察上面的数字,发现 g(x) 有正值的时候都是当x是5的倍数的时候,那么来专门看一下x是5的倍数时的情况吧:

x:    5 10 15 20  30 35 40 45  55 60 65 70  80 85 90 95  105 110 115 120
g(x): 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

仔细观察上面的红色数字,g(x)=1 时,是5的倍数,g(x)=2 时,都是 25 的倍数,g(x)=3 时,是 125 的倍数,那么就有:

g(x) = 0     if x % 5 != 0,
g(x) >= 1    if x % 5 == 0,
g(x) >= 2   if x % 25 == 0.

如果继续将上面的数字写下去,就可以发现规律,g(x) 按照 1 1 1 1 x 的规律重复五次,第五次的时候x自增1。再继续观察:

当 x=25 时,g(x)=2,此时 K=5 被跳过了。

当 x=50 时,g(x)=2,此时 K=11 被跳过了。

当 x=75 时,g(x)=2,此时 K=17 被跳过了。

当 x=100 时,g(x)=2,此时 K=23 被跳过了。

当 x=125 时,g(x)=3,此时 K=29,30 被跳过了。

进一步,可以发现如下规律:

5(=1*5), 11(=6*1+5), 17(=6*2+5), 23(=6*3+5), 29(=6*4+5), 30(=6*5), 36(=31+5), 42(=31+6+5), 48(=31+6*2+5)

这些使得x不存在的K,出现都是有规律的,它们减去一个特定的基数 base 后,都是余5,而余 1,2,3,4 的,都是返回5。那么这个基 数base,实际是 1,6,31,156,...,是由 base = base * 5 + 1,不断构成的,通过这种不断对基数取余的操作,可以最终将K降为小于等于5的数,就可以直接返回结果了,参见代码如下:

解法三:

class Solution {
public:
int preimageSizeFZF(int K) {
if (K < ) return ;
int base = ;
while (base * + <= K) {
base = base * + ;
}
if (K / base == ) return ;
return preimageSizeFZF(K % base);
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/793

类似题目:

Factorial Trailing Zeroes

参考资料:

https://leetcode.com/problems/preimage-size-of-factorial-zeroes-function/

https://leetcode.com/problems/preimage-size-of-factorial-zeroes-function/discuss/117649/4ms-Java-Math-Solution

https://leetcode.com/problems/preimage-size-of-factorial-zeroes-function/discuss/117631/C++-O(logn)-math-solution-with-explanation

https://leetcode.com/problems/preimage-size-of-factorial-zeroes-function/discuss/117821/Four-binary-search-solutions-based-on-different-ideas

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Preimage Size of Factorial Zeroes Function 阶乘零的原像个数函数的更多相关文章

  1. 793. Preimage Size of Factorial Zeroes Function

    Let f(x) be the number of zeroes at the end of x!. (Recall that x! = 1 * 2 * 3 * ... * x, and by con ...

  2. 74th LeetCode Weekly Contest Preimage Size of Factorial Zeroes Function

    Let f(x) be the number of zeroes at the end of x!. (Recall that x! = 1 * 2 * 3 * ... * x, and by con ...

  3. 【leetcode】Preimage Size of Factorial Zeroes Function

    题目如下: 解题思路:<编程之美>中有一个章节是不要被阶乘吓倒,里面讲述了“问题一:给定一个整数N,那么N的阶乘末尾有多少个0呢?例如N = 10, N! = 362800,N! 的末尾有 ...

  4. [Swift]LeetCode793. 阶乘函数后K个零 | Preimage Size of Factorial Zeroes Function

    Let f(x) be the number of zeroes at the end of x!. (Recall that x! = 1 * 2 * 3 * ... * x, and by con ...

  5. [LeetCode] Factorial Trailing Zeroes 求阶乘末尾零的个数

    Given an integer n, return the number of trailing zeroes in n!. Note: Your solution should be in log ...

  6. [LeetCode] 172. Factorial Trailing Zeroes 求阶乘末尾零的个数

    Given an integer n, return the number of trailing zeroes in n!. Example 1: Input: 3 Output: 0 Explan ...

  7. POJ 1401:Factorial 求一个数阶乘的末尾0的个数

    Factorial Time Limit: 1500MS   Memory Limit: 65536K Total Submissions: 15137   Accepted: 9349 Descri ...

  8. 【LeetCode】474. Ones and Zeroes 解题报告(Python)

    [LeetCode]474. Ones and Zeroes 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ ...

  9. [LeetCode] Minimum Size Subarray Sum 解题思路

    Given an array of n positive integers and a positive integer s, find the minimal length of a subarra ...

随机推荐

  1. beanPostProcessor与beanFactoryPostProcessor

    BeanFactoryPostProcessor的典型应用:PropertyPlaceholderConfigurer BeanFactoryPostProcessor会在所有的bean配置载入之后执 ...

  2. DirectX11 With Windows SDK--17 利用几何着色器实现公告板效果

    前言 上一章我们知道了如何使用几何着色器将顶点通过流输出阶段输出到绑定的顶点缓冲区.接下来我们继续利用它来实现一些新的效果,在这一章,你将了解: 实现公告板效果 Alpha-To-Coverage 对 ...

  3. CopyOnWriteArrayList真的完全线程安全吗

    我之前书上看到的说法是:Vector是相对线程安全,CopyOnWriteArrayList是绝对线程安全 这种说法其实有些问题,CopyOnWriteArrayList在某些场景下还是会报错的 Co ...

  4. ajax扩展、jsonp、

    偷偷上传消息,首先想到ajax 而ajax是jquery是我们封装的功能. 方式一:ajax发消息 $.ajax({ url: '/ajax3.html', type: 'GET', //或者是POS ...

  5. Linux输入法问题

    本篇博文简单介绍一下介绍Linux输入相关问题及解决方案 关于Invalid UTF-8参见https://www.baidu.com/link?url=QDh2Fa1uJcmyiaKZBzAFkNn ...

  6. Windows 下 exe 服务注册到 service 服务中

    window 下注册 exe 程序.添加到 服务中. window 注册服务方式 一. regsvr 方式 直接在 程序目录执行: Regsvr 32 命令是Windows中控件文件 ( 如扩展名为D ...

  7. es6编程建议和技巧点汇总

    大括号 特点:大括号(单独的大括号或者if等后的大括号)内是一个单独的作用域 注意点:在块级作用域内声明的函数,类似var,会被提升到大括号外,应避免在块级作用域内声明函数.如果确实需要,写成函数表达 ...

  8. 【溯源分析】疑似"摩诃草"组织最新样本分析及域名资产揭露

    1)场景 摩诃草组织(APT-C-09),又称HangOver.Patchwork.Dropping Elephant以及白象.该组织归属南亚某国,主要针对中国.巴基斯坦等亚洲国家和地区进行网络间谍活 ...

  9. Visual Studio Code 的使用方法和技巧

    VSCode是微软推出的一款轻量编辑器,采取了和VS相同的UI界面,搭配合适的插件可以优化前端开发的体验. 布局:左侧是用于展示所要编辑的所有文件和文件夹的文件管理器,依次是`资源管理器`,`搜索`, ...

  10. web富文本编辑器收集

    1.UEditor 百度的. 优点:插件多,基本满足各种需求,类似贴吧中的回复界面. 缺点:不再维护,文档极少,使用并不普遍,图片只能上传到本地服务器,如果需要上传到其他服务器需要改动源码,较为难办, ...