Leetcode276周周赛(Python)

Leetcode276周周赛

写在前面

  第一次参加周赛,写了十分钟,就把第一题写出来,就去忙其它事去了,但是后来下来看了一下题,也没有想象中那么困难,就写一篇题解记录一下吧。

第一题

在这里插入图片描述
   e a s y easy easy题,就是浪。先求整数倍 n n n,分割出 n n n个等长字符串,然后求余,没有当然最好,有 y y y个就在后面补充 k − y k-y ky f i l l fill fill字符串就行了


class Solution:
    def divideString(self, s: str, k: int, fill: str) -> List[str]:
        n = len(s)
        n1, n2 = n // k, n % k
        lis = []
        for i in range(n1):
            lis.append(s[k*i:k*i+k])
        if n2 != 0:
            s = s[-n2:] + fill * (k-n2)
            lis.append(s)
        return lis

第二题

在这里插入图片描述

  这道题需要从后往前做,因为这样可以最大限度的保证对倍数 m a x D o u b l e s maxDoubles maxDoubles的利用,如果从前往后进行动态模拟的话,很难选定翻倍的时机,但是从后往前就没有这种顾虑,只要是二的倍数,除就完了,利用完 m a x D o u b l e s maxDoubles maxDoubles的次数,剩下的减到1的次数就是 t a r g e t − 1 target-1 target1(这里target是已经递减之后的)次。


class Solution:
    def minMoves(self, target: int, maxDoubles: int) -> int:
        if target == 2:
            return 1
        if maxDoubles == 0:
            target -= 1
            return target
        times, time = 0, 0
        while 1 < target:
            if times < maxDoubles:
                if target % 2 == 0:
                    target //= 2
                    times += 1
                else:
                    target -= 1
                time += 1
            else:
                time += target - 1
                break
        return time
        

第三题

在这里插入图片描述

  简单的动态规划题目,算不上难,但是这个题目确实嘲讽到我了,因为我一开始没有写出来。
  最开始按照我的想法,我是先建立一个大小为 n = l e n ( q u e s t i o n s ) n=len(questions) n=len(questions)的数组 d p dp dp,每一个位置保存从前往后的 q u e s t i o n s [ i ] [ 0 ] questions[i][0] questions[i][0]的累加的数,然后遍历一次,把每一个不能累加到某个位置的 q u e s t i o n s [ i ] [ 0 ] questions[i][0] questions[i][0]减去就行了,写出来代码如下:


class Solution:
    def mostPoints(self, questions: List[List[int]]) -> int:
        n = len(questions)
        dp = [0] * n
        for i in range(n):
            dp[i] = questions[i][0] + dp[i-1]
        for j in range(n):
            k = questions[j][1]
            for i in range(1,k+1):
                if i + j < n:        #确定遍历范围在数组大小内
                    dp[i+j] -= questions[j][0]
        return max(dp)

  咋一看没有什么错误,但是实际上是有的。比如说测试用例[[1,1],[2,2],[3,3],[4,4],[5,5]],最大的是 2 + 5 = 7 2+5=7 2+5=7,但是递减到 5 5 5的时候由于 1 1 1的范围覆盖到 2 2 2,与 2 2 2无法兼容,筛选条件却没办法满足这一条,导致我的最大值比应该的值大。
  为了解决这个问题,我思考是不是要添加判定条件,但是却始终想不出好的限制条件。于是转化思路。从后往前遍历。
  其实思路大同小异,前面是先累加,最后再减去不符合条件的,但是由于覆盖范围的原因筛选不完。所以不累加,直接从后往前,满足条件的加上,不满足的就不加。限制条件就还是覆盖范围而已。


class Solution:
    def mostPoints(self, questions: List[List[int]]) -> int:
        n = len(questions)
        dp = [0] * n
        for i in range(n - 1, -1, -1):
            j = i + questions[i][1] + 1
            if i == n-1:
                if j < n:
                    dp[i] = questions[i][0] + dp[j]
                else:
                    dp[i] = questions[i][0]
            else:
                dp[i] = max(dp[i + 1], questions[i][0] + (dp[j] if j < n else 0))        #这样写要简单一点
        return dp[0]

第四题

在这里插入图片描述
  我们先来做一个简单的分析,最理想的状态就是同时使用 t i m e = ⌊ s u m ( b a t t e r i e s ) n ⌋ time=\lfloor\frac{sum(batteries)}{n}\rfloor time=nsum(batteries)分钟。但天不遂人愿,有的时候它就是不让你这么简单,最简单的反例就是数组中有时间大于 t i m e time time的时候,我们只要排除掉数组中大于 t i m e time time(注意,这里的 t i m e time time是每一次计算之后的time,不是一开始固定不变的 t i m e time time)的个数,然后再次计算 t i m e time time,一直到数组中的时间小于该数组下的 t i m e time time,这就是我们所需要的 t i m e time time了。
  最开始我写的代码如下:


class Solution:
    def maxRunTime(self, n: int, batteries: List[int]) -> int:
        def judge(batteries,n):
            time = sum(batteries) // n
            for i in range(len(batteries)):
                if batteries[i] > time:
                    batteries.remove(batteries[i])
                    n -= 1
            time = sum(batteries) // n
            for j in range(len(batteries)):
                if batteries[j] > time:
                    return judge(batteries,n)
            return time
        return judge(batteries,n)

  他能通过大部分测试用例,但是当我创建测试用例 5 , [ 5 , 1 , 9 , 5 , 5 ] 5,[5,1,9,5,5] 5,[5,1,9,5,5](我自己创建的用例)会出现数组越界,所以就很尴尬。然后换了个写法


class Solution:
    def maxRunTime(self, n: int, batteries: List[int]) -> int:
        batteries.sort()
        batteries.reverse()                  #将数组从大到小排列,保证遍历到的是最大值
        '''
        实不相瞒,在写这篇文章的时候,我觉得把上面那串代码数组这样排列一下,也就能对,
        但是看过前面我的文章的人都知道我是什么德行,着实有点难,大家可以自己去试试,
        要是能对别忘了回来告诉我。
        '''
        start_time = sum(batteries)
        for i in range(len(batteries)):
            if batteries[i] <= start_time // n:
                return start_time // n
            start_time -= batteries[i]
            n -= 1

写在后面

  讲几件事情吧,先是刷题的一些心得,我是这个寒假开始才有意识、有规律的开始刷题的,刷了几次题,写了两套题解,也有了一些想法。

  其中感受最深的是一开始刷题的时候不注重数学规律,拿到题目的第一想法就是 模 拟 实 现 模拟实现 ,比如像第四题,第一想法就是建立电脑列表和电池列表进行一一匹配,然后就是 动 态 规 划 动态规划 的题目,这种心态真的特别强烈,但是这种想法是要不得的,算法更加注重的数学逻辑,这是我们应该特别注意的。

  这是我特别深的体会,写出来与大家分享,希望与诸君共勉。
  第二就是我文章的问题,由于我是一个菜鸟,所以我深能体会大家(假装很多人和我一样菜)看网络上一些大佬的题解的那种无奈,他就告诉你,动规、贪心、回溯…你说他什么都没写吧,人家大佬愿意和你分享代码就很不错了,但是你说他写了吧,嗯…
  所以我写题解一开始就是两个定位,一是反馈自己的学习情况,二是写一些菜鸟也能看懂的题解,所以希望大家监督,时刻提醒我的文章写得怎么样,是否有错,又或者当你遇见 看 不 懂 的 知 识 点 看不懂的知识点 我却 没 有 详 细 没有详细 书写的时候,请尽快向我反应。我会尽快改正的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值