首页 > 其他分享 >图解LeetCode——793. 阶乘函数后 K 个零(难度:困难)

图解LeetCode——793. 阶乘函数后 K 个零(难度:困难)

时间:2023-05-23 11:07:02浏览次数:32  
标签:10 793 25 末尾 我们 阶乘 出现 LeetCode


一、题目

 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 的数量。

二、示例

2.1> 示例 1:

【输入】k = 0
【输出】5
【解释】0!, 1!, 2!, 3!, 和 4! 均符合 k = 0 的条件。

2.2> 示例 2:

【输入】k = 5
【输出】0
【解释】没有匹配到这样的 x!,符合 k = 5 的条件。

2.3> 示例 3:

【输入】 k = 3
【输出】 5

提示:

  • 0 <= k <= 10^9

三、解题思路

根据本题的描述,知道了一个公式,即:f(x) = k,用于表示x的阶乘计算出结果后,这个值的末尾有k个0。比如:f(5)=1,因为5! = 1 * 2 * 3 * 4 * 5=120,因为120这个值末尾有1个0,所以f(5)=1。那么,如何让结果的末尾能有0呢? 只要我们任何数值乘以10,结果就会多一个0,比如:3 * 10 = 30,20 * 10 = 200……;那么,因为10 = 2 * 5,所以我们将10再次拆分,可以拆分出2和5,也就是说,在阶乘中,所有的整数,拆分为质数后,有多少对2和5,结果就会有多少个0;那么我们就来演示一下从0!到11!,他们的拆分情况,具体如下图所示:

图解LeetCode——793. 阶乘函数后 K 个零(难度:困难)_二分法查找

在上图中,我们可以看到,对于“2”来说,2、4、6、8这4个数,可以拆出6个“2”;对于“5”来说,5、10这2个数,可以拆出3个“5”;所以,通过上面的规律我们可以看出,2出现的次数是远远大于5出现的次数的,所以,我们就可以将规则简化为:“在一个数的阶乘中,5出现了n次,那么在结果中,末尾就会有n个0”。

我们继续往下分析,通过上图我们还发现了一个规律,那就是,每隔5个数,就会出现一个“5”,例如:0、5、10、15、20、25、30……,我们可以分别将其理解为0=0*5、5=1*5、10=2*5、15=3*5、20=4*5、25=5*5、30=6*5……;那么我们发现每隔5个数字(从0*5 ~ 4*5),就会出现1次5。而我们发现,当到25的时候,出现了特殊情况,也就是25可以拆分为5 * 5,那就是说,比25之前的所有数字都多出一个“5”,具体如下图所示:

图解LeetCode——793. 阶乘函数后 K 个零(难度:困难)_后端_02

那么除了25之外,还有其他特殊的吗?当然有,比如125=5*5*5,那么就相当于出现了3次5625=5*5*5*5,那么就相当于出现了4次5;所以,我们可以得出以下结论:在以数字n进行阶乘的时候,每隔5个数,会出现一次5,每隔25个数,会出现两次5,每隔125次,会出现三次5……,以此类推。所以,假如给我们一个数字n,它到底有多少个5,那也就相当于结果的末尾有多少个0,计算公式为:n/5 + n/25 + n/125 + N/625 + ……;其实也就是:n/5 + n/(5*5) + n/(5*5*5) + n/(5*5*5*5) + ……,具体含义如下图所示:

图解LeetCode——793. 阶乘函数后 K 个零(难度:困难)_算法_03

了解了上述我们总结出的结果,那么对于这道题,我们就可以将其翻译为:能够满足某个值x(x为非负整数)的阶乘,可以出现k个5的数量。那么我们如果可以获得第一次满足5出现了k次,和第一次满足5出现k+1次,并且两者相减,结果就是满足了5可以出现k次的数量了。我们可以举例,假如求k=1,即:末尾1个“0”出现的次数,第一次满足k=1是5的阶乘,第一次满足k=2是10的阶乘,那么最终结果就是10-5=5,即:满足末尾1个“0”的数量为5(包含:5!6!7!8!9! 一共5个)。具体详情,如下图所示:

图解LeetCode——793. 阶乘函数后 K 个零(难度:困难)_二分法查找_04

又因为阶乘的特殊性,它计算的结果就是单调递增的,那么我们就可以通过二分法快速的计算出满足了“5”第一次出现了k次的位置是哪里了。但是,既然要用二分法查找,那么我们就需要确定查找的范围,最大的查找范围需要设置多少合适呢?我们还来看看上面我们得出的一些规律,我们曾经总结过,每5次数字过后,才会出现1次5,那么如果我们要寻找第一次出现了k次5的话,我们要查找的范围就是5k了。所以,我们的查找范围确定为[0, 5k]。比如,我们要找k=1,即:第一次5出现的位置,那么我们的查找范围就是[0, 5];如果k=2,二分法查找的范围就是[0,10]。

但是大家有没有发现一个规律,就是这个题的答案其实不是0就是5,所以,我们其实只需要判断k的一次出现的位置是否存在即可,如果存在,那么我们直接return 5;如果不存在,则直接return 0即可。具体代码实现,请参照如下。

四、代码实现

class Solution {
    public int preimageSizeFZF(int k) {
        long start = 0L, end = 5L * k, mid;
        while(end >= start) {
            mid = start + (end - start) / 2;
            long n = 5L, nums = 0L;
            while (n <= mid) {
                nums += mid / n;
                n *= 5;
            }
            if (nums == k) return 5;
            if (nums < k) start = mid + 1;
            else end = mid - 1;
        }
        return 0;
    }
}

图解LeetCode——793. 阶乘函数后 K 个零(难度:困难)_java_05

今天的文章内容就这些了:

写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享

更多技术干货,欢迎大家关注公众号“爪哇缪斯” ~ \(^o^)/ ~ 「干货分享,每天更新」

标签:10,793,25,末尾,我们,阶乘,出现,LeetCode
From: https://blog.51cto.com/u_15003301/6330102

相关文章

  • 图解LeetCode——剑指 Offer 34. 二叉树中和为某一值的路径
    一、题目给你二叉树的根节点root和一个整数目标和targetSum,找出所有从根节点到叶子节点路径总和等于给定目标和的路径。叶子节点是指没有子节点的节点。二、示例2.1>示例1:【输入】root=[5,4,8,11,null,13,4,7,2,null,null,5,1],targetSum=22【输出】[[5,4,11,2],[5,......
  • 图解LeetCode——662. 二叉树最大宽度(难度:中等)
    一、题目给你一棵二叉树的根节点root,返回树的最大宽度。树的最大宽度是所有层中最大的宽度。每一层的宽度被定义为该层最左和最右的非空节点(即,两个端点)之间的长度。将这个二叉树视作与满二叉树结构相同,两端点间会出现一些延伸到这一层的null节点,这些null节点也计入长......
  • 图解LeetCode——658. 找到 K 个最接近的元素(难度:中等)
    一、题目给定一个排序好的数组 arr,两个整数k和x,从数组中找到最靠近x(两数之差最小)的k个数。返回的结果必须要是按升序排好的。整数a比整数b更接近x需要满足:|a-x|<|b-x|或者|a-x|==|b-x|且a<b二、示例2.1>示例1:【输入】arr=[1,2,3,4,5],k=......
  • 图解LeetCode——剑指 Offer 36. 二叉搜索树与双向链表
    一、题目输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。二、示例为了让您更好地理解问题,以下面的二叉搜索树为例:我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对......
  • 图解LeetCode——782. 变为棋盘(难度:困难)
    一、题目一个 n*n 的二维网络 board 仅由 0 和 1 组成 。每次移动,你能任意交换两列或是两行的位置。返回将这个矩阵变为 “棋盘”  所需的最小移动次数 。如果不存在可行的变换,输出-1。“棋盘”是指任意一格的上下左右四个方向的值均与本身不同的矩阵。二、示例......
  • 图解LeetCode——1460. 通过翻转子数组使两个数组相等(难度:简单)
    一、题目给你两个长度相同的整数数组 target 和 arr 。每一步中,你可以选择 arr 的任意非空子数组 并将它翻转。你可以执行此过程任意次。如果你能让arr 变得与target 相同,返回True;否则,返回False。二、示例2.1>示例1:【输入】target=[1,2,3,4],arr=[2,4,1,3]......
  • 图解LeetCode——剑指 Offer 07. 重建二叉树
    一、题目输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。二、示例2.1>示例1:【输入】preorder=[3,9,20,15,7],inorder=[9,3,15,20,7]【输出】[3,9,20,null,null,15,7]2.2>示例2:【输入】pr......
  • 图解LeetCode——剑指 Offer 29. 顺时针打印矩阵
    一、题目输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。二、示例2.1>示例1:【输入】matrix=[[1,2,3],[4,5,6],[7,8,9]]【输出】[1,2,3,6,9,8,7,4,5]2.2>示例2:【输入】matrix= [[1,2,3,4],[5,6,7,8],[9,10,11,12]]【输出】[1,2,3,4,8,12,11,10,9,5,6,7]限......
  • 图解LeetCode——剑指 Offer 15. 二进制中1的个数
    一、题目编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为'1'的个数(也被称为 汉明重量)。二、示例2.1>示例1:【输入】n=11(控制台输入00000000000000000000000000001011)【输出】3【解释】输入的二进制串000000000000000000000000000010......
  • 图解LeetCode——654. 最大二叉树(难度:中等)
    一、题目给定一个不重复的整数数组 nums。 最大二叉树 可以用下面的算法从 nums递归地构建:1>创建一个根节点,其值为 nums中的最大值。2>递归地在最大值 左边 的 子数组前缀上 构建左子树。3>递归地在最大值右边的 子数组后缀上 构建右子树。返回 nums构建的......