题目
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,找出返回能满足 f(x) = k 的非负整数 x 的数量。
示例1
输入: k = 0 输出: 5 解释: 0!, 1!, 2!, 3!, 和 4! 均符合 k = 0 的条件。
示例2
输入: k = 5 输出: 0 解释: 没有匹配到这样的 x!,符合 k = 5 的条件。
示例3
输入: k = 3 输出: 5
- 难度:困难
- 使用语言:TypeScript
- 链接:阶乘函数后 K 个零
前段时间太忙,没时间刷算法题,周日在家总算是空了下来,想着停了好几天了今天一定得做一道题目,结果好嘛,直接先送我一道困难题来惩罚我😭。
在做这道题目之前可以先完成一道难度为中等的题目阶乘后的零,
求阶乘后的零
给定一个整数
n,返回n!结果中尾随零的数量。提示
n! = n * (n - 1) * (n - 2) * ... * 3 * 2 * 1
示例1
输入: n = 3 输出: 0 解释: 3! = 6 ,不含尾随 0
示例2
输入: n = 5 输出: 1 解释: 5! = 120 ,有一个尾随 0
示例3
输入: n = 0 输出: 0
这道题目需要用到数学方法来解决,这种题目代码一般不会太长,但是得想的到才行。
阶乘的概念:n! = 1 * 2 * 3 * ······ * n
首先思考一下为什么尾部会出现0呢?
- 任何一个数当乘以10或者10的倍数时,末尾的0都会不断增加,所以每个阶乘中出现10的倍数,末尾的0就加一。
- 5乘以任意的偶数,都可以得到10的倍数,并且10也是5的倍数。
- 任意阶乘数字的偶数的数量一定是大于5的倍数的数字的。
- 25可以拆分为 5 * 5,每一个5都可以给末尾提供一个0,所以25是可以给末尾提供两个0的。同理50,75也可以提供两个0,125可以提供三个0.
- 结合以上几点,问题可以转化为n!可以拆分出几个5来,这样问题就简单了。
上代码
function trailingZeroes(n: number): number {
let res: number = 0
while (n !== 0) {
n = Math.floor(n / 5)
res += n
}
return res
};
解释一下这段代码的意思
- 每次循环都把n除以5。
- 第一次循环里向下取整得到的数字,是1~n中可以拆分出1个及以上5的数字有几个。
- 第二次循环得到的数字是可以拆分出2个5的数字有几个。
- 以此类推,把每次循环得到的值相加就是可拆分出的5的个数。
例如:
100 / 5 = 20,1 ~ 100中可以拆分出1一个及以上的5有20个
20 / 5 = 4,1 ~ 100中拆分出2个及以上5的数有4个:25,50,75,100
4 / 5 向下取整得到0,所以在1 ~ 100中,没有数字可以拆成3个5
最后得到的值即20 + 4 = 24,即100!末尾有24个0
阶乘函数后 K 个零
现在回到这道题,我们已经有办法可以解决n!末尾可以得到几个0,现在要我们解决的是末尾有k个0的数字有几个。
根基上一题提供的例子,我们可以很快得到末尾0个数小于等于23个的n有100个,即0! ~ 99!。
我们把这个数字即为n(23)。
那么有且仅有24个0的个数为n(24) - n(23)。
现在还需要解决这个n(k)函数怎么算。
可以使用二分法来求解n函数,左边界肯定是0,右边界可以得出是小于k * 5的
上最后的代码
function preimageSizeFZF(k: number): number {
return help(k + 1) - help(k)
};
function help(k): number {
let max: number = k * 5
let min: number = 0
while (max >= min) {
let mid: number = Math.floor((max + min) / 2)
if (trailingZeroes(mid) < k) {
min = mid + 1
} else {
max = mid - 1
}
}
return max
}
function trailingZeroes(n: number): number {
let res: number = 0
while (n !== 0) {
n = Math.floor(n / 5)
res += n
}
return res
};
总结
- 这道题目的难点在于要把数学关系弄清楚,能想到末尾0的个数即是能拆分出5的个数这道题就有思路了。
- 用数学方式解决问题不太好想到,但是这种代码一般不会太长。
这道题靠自己没做出来,看了好一会的题解才算解决😮💨