蓝桥杯刷题014——求阶乘(二分法)

这篇具有很好参考价值的文章主要介绍了蓝桥杯刷题014——求阶乘(二分法)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

求阶乘 

蓝桥杯2022省赛题目

问题描述

满足 N ! 的末尾恰好有 K 个 0 的最小的 N 是多少?

如果这样的 N 不存在输出 −1 。

输入格式

一个整数 K 。

输出格式

一个整数代表答案。

样例输入

2

样例输出

10

评测用例规模与约定

对于 30% 的数据, 1≤K≤10^6.

对于 100% 的数据, 1≤K≤10^18.

思路: 

题目大意:求满足N!的末尾恰好有K个0的最小的N,如果这样的N不存在,返回-1

解法一:暴力法

        遍历1~10^18(题目中100%的数据规模)内所有数,对每个数求阶乘,再计算末尾0的个数,最后判断是否为K个0,很明显是超时了(看下面代码分析)。但可以得到部分的分数,没有时间的话可以这样简单处理。

        代码分析:这个是计算末尾0的个数的代码,很明显在这个环节就没办法达到100%数据的要求,因为1≤K≤10^18,而这个代码复杂度是O(n),要计算10^18次,但蓝桥杯计算量一般不超过10^8,所以用暴力法计算是超时的。 

res = 0     # 统计末尾0的个数
while m % 10 == 0:
    res+=1
    m//10    # 去掉最后一位

解法二: 

解题关键给出一个N,如何快速计算它的阶乘中末尾0的个数?

  • 思考1:什么样的数,相乘后能够产生0?

10=2*5

20=2*2*5
7200=72*2*5*2*5
我们可以发现每个数字末尾的每个0都可以看成是2和5相乘得到
所以我们可以对题目中样例进行分析:10!=1 * 2 * 3 * 4 * 5* 6 * 7 * 8 * 9 * 10,我们发现10!内有一对现成的2和5,但样例输出是2,说明还有一对2和5,没错,只要把10进行分解成2*5就可以再得到一对,这样两对2和5说明10的阶乘末尾有2个零。

结论:给定一个数的阶乘,计算它的因子中2*5出现的次数,即可确定末尾0的个数 

  • 思考:2:找2*5的数目,因子2是否需要寻找?

不需要。通过10!=1 * 2 * 3 * 4 * 5* 6 * 7 * 8 * 9 * 10可以发现,因子5只有在5和10中才有。但因子2在2,4,6,8,10中都存在,出现2多5少的现象,所以只需要找到稀有的因子5即可,因为因子2是肯定有剩余的。

问题转换:

求N的阶乘尾部0的个数      求N的阶乘中因子5的个数
        对阶乘中的因子5进行分析,1 2 3 4 5…10 …15…20…25…30…35… 50…55… 75…100…105…125…,可以发现当到24时,前面每隔5都会都会有一对2和5,共有4对。但在25时会出两个5(两对2和5),总共就有6对,如果你输入5的话,没有末尾为5个0的阶乘,则返回-1。在124之前每隔25会出两对,但125会出三对。把前面出现的5加起来总共有31个,但这样很麻烦,有没有更容易操作的方法呢?看看下面的操作:

蓝桥杯刷题014——求阶乘(二分法)

         为什么是这样算呢?是因为我们先把含有一个及以上5的25个数全部取出一个5加到总数num,那么本来一个5的数就变成0个(可以忽略),本来两个5的数变成一个5的数,本来3个5的变成二个5的。再这样对原本含有二个及以上5的5个数(现在是含有一个及以上5的数)操作一次,只剩下一个含5的数,最后再对含5的1个数取出一个5加到总数num,这样就把全部的因子5转移到了总数num。

结论:求N的阶乘中因子5的个数,将N每次除以5求和即可。

定义求一个整数阶乘末尾0的个数的函数:

def cal_zero(N):
    res = 0   # 统计0的个数
    while N:
        N //= 5
        res += N
    return res

复杂度:每一次变成原来的五分之一,所以复杂度为,是logN级别的,计算10^18的数只需要算26次即可,非常高效!

注意:题目中 1≤K≤10^18的K是指整数阶乘末尾0的个数的范围,不是整数的范围,说明整数范围可能更大,我们以10^19的整数试一下,看看阶乘末尾0的个数能不能大于10^18。

def cal_zero(N):
    res = 0  # 统计0的个数
    while N:
        N //= 5
        res += N
    return res

N = 1e19
print(cal_zero(N))  # 2.5e+18

        很显然,10^19的整数阶乘末尾有2.5e+18个0,大于题目100%数据大小,是满足要求的。所以N可以取10^19来计算。

        上面只是求出了整数阶乘末尾0的个数,还需要找出满足末尾K个0的最小整数,下面用二分法来求解。

二分法登场啦!

使用条件:更小的N对应的是小的尾0个数,更大的N对应的是大的0个数,所以末尾0的个数是一个递增的有序数列,可以用二分法来求解。
定义一个check()函数:将所有从1到N的阶乘分成尾部0个数<k的左半部分和>=k的右半部分,二分结束后检查R位置(因为R是满足≥check()的最小值)的尾部0个数是否为k即可,若不是即返回-1。

蓝桥杯刷题014——求阶乘(二分法)

def check(k):
    L,R=1,int(1e19)    
    while L+1!=R:
        mid = (L+R)//2
        if cal_zero(mid)>=k:    
            R = mid
        else:
            L=mid
    if cal_zero(R)==k:  # cal_zero(r):满足阶乘末尾0≥k的最小整数
      return R
    else:               # 没有阶乘末尾k个0的整数
      return -1   

 二分法的复杂度也是O(logN),所以算法复杂度为文章来源地址https://www.toymoban.com/news/detail-411613.html

代码演示: 

k=int(input())
def cal_zero(N):
    res = 0   # 统计末尾0的个数
    while N:
        N //= 5
        res += N
    return res
def check(k):
    L,R=1,int(1e19)    
    while L+1!=R:
        mid = (L+R)//2
        if cal_zero(mid)>=k:    
            R = mid
        else:
            L=mid
    if cal_zero(R)==k:  # cal_zero(r):满足阶乘末尾0≥k的最小整数
      return R
    else:               # 没有阶乘末尾k个0的整数
      return -1   
print(check(k))

到了这里,关于蓝桥杯刷题014——求阶乘(二分法)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 初探二分法

    初探二分法

    智能化校园:深入探讨云端管理系统设计与实现(一) 智能化校园:深入探讨云端管理系统设计与实现(二) 题目:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 提示: 你可以

    2024年01月25日
    浏览(15)
  • 二分法简单题

    2024年01月24日
    浏览(16)
  • 二分法相关使用

    二分法相关使用

    在线OJ:704. 二分查找 有序数组下的二分思路如下: 由于这里是有序数组, 我们可以可以先得到中点位置, 中点可以把数组分为左右两边; 如果中点位置的值等于目标值, 直接返回中点位置; 如果中点位置的值小于目标值, 则去数组中点左侧按同样的方式查找; 如果中点位置的值大

    2024年02月07日
    浏览(12)
  • 【算法】—二分法详解

    【算法】—二分法详解

    ①定义: 二分查找算法也称折半搜索算法,对数搜索算法,是一种在 有序数组 中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素

    2024年02月09日
    浏览(11)
  • 【二分查找】一文带你掌握二分法 (附万能模板)

    【二分查找】一文带你掌握二分法 (附万能模板)

    一、简介 哪怕没有学过编程的同学,也许不知道二分法这个名字,但也一定接触过它的核心思想。不了解的同学也没关系,我用一句话就能概括出它的精髓: 将一个区间一分为二,每次都舍弃其中的一部分。 二分法能够极大地降低我们在解决问题时的时间复杂度。假如你要

    2024年01月19日
    浏览(13)
  • 【剑指Offer】二分法例题

    【剑指Offer】二分法例题

    链表是数据结构中重要的一个章节,他的重要性也不言而喻,在未来不管是笔试还是面试都会遇到这类的题目,所以接下来我就会把一些链表的常考的题目全部整理出来供大家学习指正。 题目链接 描述: 给定一个长度为n的数组nums,请你找到峰值并返回其索引。数组可能包

    2023年04月13日
    浏览(12)
  • 非线性方程二分法

    优点:算法直观、简单、总能保证收敛;局限:收敛速度慢、一般不单独用它求根,仅为了获取根的粗略近似 设 f ( x ) f(x) f ( x ) 在 [ a , b ] [a,b] [ a , b ] 上连续、严格单调、满足条件 f ( a ) f ( b ) 0 f(a)f(b)0 f ( a ) f ( b ) 0 则在区间 [ a , b ] [a,b] [ a , b ] 内必有一根 x ∗ x^* x ∗ 。通

    2024年02月04日
    浏览(16)
  • 牛顿法、割线法、二分法

    牛顿法、割线法、二分法

    牛顿法求解非线性方程组 割线法求解非线性方程组 二分法求解根号3  另外,今天上机课写程序时,发现不同的起始点可以收敛到不同的零点。也许这是一个新的值得研究的地方。 看来,计算数学也是这样,光听理论无法实现大的突破,也没法产生好的想法,必须在实践应用

    2024年02月05日
    浏览(16)
  • 算法:二分法---寻找H指数

    算法:二分法---寻找H指数

    1、题目: 给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数 。 根据维基百科上 h 指数的定义: h 代表“高引用次数” ,一名科研人员的 h 指数 是指他(她)至少发表了 h 篇论文,并且每篇论文 至少 被引用

    2024年02月08日
    浏览(12)
  • 06-C++ 基本算法 - 二分法

    06-C++ 基本算法 - 二分法

    在这个笔记中,我们将介绍二分法这种基本的算法思想,以及它在 C++ 中的应用。我们将从一个小游戏猜数字开始,通过这个案例来引出二分法的概念。然后我们将详细讲解什么是二分法以及它的套路和应用。最后,我们还会介绍 C++ STL 中的二分查找函数。让我们一起来探索

    2024年02月16日
    浏览(10)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包