• Python解题 - CSDN周赛第9期


    这次比赛的题目难度又降低不少,基本上都是出现过的经典老题,最后一题更是曾多次出现在CSDN的每日一练中,看来官方是想提醒大家多多参与每日一练啊。


    第一题:小艺读书

    书是人类进步的阶梯。 小艺每周因为工作的原因会选择性的每天多读几页或者少读几页。

    小艺想知道一本n页的书她会在周几读完。

    分析

    一开始以为是老题——给定n页的书,每天读3页或4页,然后想在某一天读完,有多少种读法。仔细一读,发现变得更简单了:题目给出了一个包含7个元素的列表,表示每天读多少页。然后题目就可以通过不断用总页数 n 减去每天读书的页数,直到 n 等于或小于0为止,即可得到需要读多少天。

    唯一需要注意的是当读书的天数超过一周时,结果大于等于7,需要重新变成0开始。这也很简单,只要对7取余即可。该题简单到连结果都不需要转化为星期几,直接返回0到6的数字即可。

    参考代码

    1. def solution(n, pages):
    2. result = 0
    3. while n>0:
    4. n -= pages[result%7]
    5. result += 1
    6. return result%7

    第二题:鬼画符门之宗门大比拼

    给定整数序列A。求在整数序列A中连续权值最大的子序列的权值。

    分析

    题目标题起得很唬人,其实也是经典老题:求整数序列中连续子序列之和的最大值,LC原题。前几天在CSDN问答频道也有人问过,问哥还回答过,可惜没有被采纳。

    解法有很多种,暴力解法也可,就是把所有的子序列求出来,然后比较它们的和,返回最大值。不过这种解法有可能因为耗时太长而无法通过测试,问哥也没有尝试。

    时间复杂度为O(n)的解法是使用贪心算法或动态规划。算法的核心思想是:对序列中每一个整数而言,如果之前的序列之和是负数,就不相加。因为如果加上之前的序列,反而比自己本身的值还要小,而我们要找最大值,显然不符合,所以最大子序列应该从自己开始算起。

    所以,额外定义两个变量,一个用来记录连续相加的子序列之和,一个用来记录最大的子序列之和。使用 max() 函数即可完成比较。当for循环遍历完一遍列表,即可返回结果。

    唯一要注意的一点是,两个变量在初始化的时候,不需要表示“极小值”,而是直接赋值列表的第一个元素即可。这样可以假定列表只有一个元素,那么最大子序列当然就是第一个元素。然后遍历的时候从第二个元素开始比较。

    参考代码

    1. def solution(n, arr):
    2. result = temp = arr[0]
    3. for i in arr[1:]:
    4. temp = max(i, i+temp)
    5. result = max(result, temp)
    6. return result

    第三题:硬币划分

    有1分,2分,5分,10分四种硬币,每种硬币数量无限,给定n分钱(n<=100000),有多少中组合可以组成n分钱?

    分析

    四道题里稍微有点难度的,但也是老题。首先常识告诉我们,用暴力的穷举法一定能做出来。无非是四层嵌套循环abcd,分别表示1分、2分、5分、10分四种硬币,然后当下面等式成立的时候,结果加一:a+2*b+5*c+10*d=n

    时间复杂度为O(n^{4}) 。因为这种方法太直观了,问哥一上来就试过,果不其然,无法通过。

    该使用万能的动态规划了(此题其实属于动态规划中的完全背包类型)。

    这里需要在逻辑上稍微理一理。我们要使用1、2、5、10分四种硬币得到n,那这个可能的方法数量可以由什么(状态)推导而来呢?我们用f(n)表示使用四种硬币组成价值n的方法数,在可能的结果里先拿走一枚10分的硬币(假设n>=10),那么剩下的硬币总价值为n-10。相对应地,f(n-10)表示使用这四种硬币有多少种方法可以组合成 n-10。假设规定最后这10分的价值只允许使用10分的硬币,那很显然,f(n)=f(n-10)。但是这10分、乃至价值n都同样可以使用1、2、5硬币来得到,所以我们要加上如果只使用1、2、5分硬币组成n的方法数,用f'(n)表示的话可以得到以下公式:f(n)=f(n-10)+f'(n)

    不难发现,如果我们在f'(n)里拿走5分硬币,用f''(n)表示只使用1、2两种硬币得到n的方法数,同样可以推导出

    f'(n)=f'(n-5)+f''(n)

    为了使表达更清楚,我们更换一下f的表示方法,可得以下公式:

    f^{2}(n)=f^{2}(n-2)+f^{1}(n)

    f^{5}(n)=f^{10}(n-5)+f^{2}(n)

    f^{10}(n)=f^{10}(n-10)+f^{5}(n)

    其中f^{2}(n)f^{5}(n)f^{10}(n)分别代表:只使用1分2分硬币、只使用1分2分5分硬币、使用全部4种硬币得到价值 n 的方法数。而f^{1}(n),也就是只使用1分硬币的情况,方法数必然恒定是1,所以无须推导。

    你可能会有一种“错觉”:这样会不会漏掉一些可能,比如那种“在前面使用了四种硬币,而在最后10分的时候只使用了1、2、5分硬币”?其实不然,这种情况必然已经包含在了公式的计算结果里,因为硬币是没有使用顺序的,你可以假设拿走的那一枚10分的硬币,是存在于“前面使用了四种硬币”里的某一枚(总的10分硬币的数量相同),这样,该情况就必然包含在了结果里。

    根据上述推导,我们可以列出动态规划图表如下:

    价值(n)012345678910111213
    只使用1分硬币(f^{1}(n)11111111111111
    只使用1分、2分硬币(f^{2}(n)11223344556677
    只使用1分、2分、5分硬币(f^{5}(n)112234567810111314
    使用全部四种硬币(f^{10}(n)112234567811121516

    最终我们要返回的结果就是图表的右下角数字,如果列出二维数组的话,也就是dp[3][n]。 

    参考代码

    1. def solution(n):
    2. result = [[1]*(n+1) for i in range(4)]
    3. for i in range(2,n+1):
    4. k = 1
    5. for j in [2,5,10]:
    6. if i>=j:
    7. result[k][i] = result[k][i-j]+result[k-1][i]
    8. else:
    9. result[k][i] = result[k-1][i]
    10. k += 1
    11. return result[3][n]%1000000007

    该题因为要考虑到传统编程语言可能会存在得出的结果太大,产生数据溢出的问题,从而要求得到的结果对1000000007取模。所以,在返回的时候要将得到的结果进行模运算。


    第四题:饿龙咆哮-逃离城堡

    小艺酱误入龙族结界,被恶龙带回城堡,小艺酱决定逃离城堡,逃离龙族结界.。

    总路程为c, 小艺酱的速度是vp,饿龙速度为vd。饿龙会在t小时后发现小艺酱出逃。

    小艺酱担心自己跑不出去,准备了好多珍宝。 每当饿龙追上自己的时候小艺酱就会丢下一个珍宝,饿龙捡到珍宝会返回自 己的城堡进行研究,研究f小时后,再出城堡追赶小艺。

    小艺想知道自己至少需要丢多少珍宝才能让自己安全逃出结界。

    分析

    CSDN每日一练里的题目,也是数学里再熟悉不过的追赶题——速度快的追速度慢的,问两人(物)相遇的时候,速度快的跑了多少路。因为每次饿龙捡到珍宝后,都要退回城堡再出发,于是本题就可以转化为,小艺要丢几次珍宝,才使得最后一次饿龙追不上小艺。而每次追赶的时候,小艺都先跑了 t 时间的路,所以 vp*t 就是每次追赶时的初始距离,设 x 为饿龙追上小艺所花的时间,易得 x = vp*t/(vd-vp),而vd*x 则等于饿龙追上小艺时跑的路程,于是可得,当最后一次追赶 大于结界总路程 c 的时候,代表饿龙追不上,而小艺成功逃出结界。

    参考代码

    1. def solution(vp, vd, t, f, c):
    2. result = 0
    3. if vd<=vp: return 0
    4. x = vp*t/(vd-vp)
    5. while vd*x
    6. result += 1
    7. t += 2*x+f
    8. x = vp*t/(vd-vp)
    9. return result

    虽然看起来似乎是官方在号召大家多多参加CSDN的每日一练,但问哥不得不吐槽,每日一练中的题目真的是文字描述问题太多,常常让人看不懂,而且测试数据也存在问题。问哥已经亲身遇到过其他平台的真题在CSDN无法通过测试。只希望官方能够重视起来,尽快对在线答题系统进行优化吧。

  • 相关阅读:
    [Python进阶] 获取计算机相关信息:Psutil
    ELK介绍以及搭建
    C#学习笔记--复杂数据类型、函数和结构体
    C++ 中 API 兼容与 ABI 兼容万字详解
    王府街10号院团建笔记
    tensor和numpy相互转换
    Oracle SQL基础
    mpls详解
    MaixII-Dock(v831)学习笔记——UART
    芯片SoC设计你了解吗?
  • 原文地址:https://blog.csdn.net/soonway2010/article/details/127831978