LeetCode笔记:Biweekly Contest 40 比赛记录

0. 赛后总结

这次的比赛也算是把我震惊到了,前三题都把条件设置的极为简单,以至于几乎不用考虑什么特殊边界条件的情况,导致整体问题难度就下降了好多,第四题其实还是有点麻烦,真要想一个好的动态规划算法反正我是一下子没啥好的思路,然后尝试了一下暴力求解,居然一次过了,顿时就惊呆了。

这次也是历史性地打入了世界前50,差点打进前25(27名),国内更是19名,直接出现在了第一页上,简直是被自己惊呆了,只要leetcode不要再出什么奇葩操作,我觉得我能把这次的成绩吹上好久😂

1. 题目一

给出题目一的试题链接如下:

1. 解题思路

这一题要考虑最优的代码实现其实还是蛮烦的,不过由于限制了字符串长度不会超过100,因此耗时再怎么样也不会太过长,因此,我们就直接用最暴力的方法,直接不断地增长待检测字符串,直到其不出现在原始字符串序列当中,然后统计其累加次数即可。

2. 代码实现

给出python代码实现如下:

class Solution:
    def maxRepeating(self, sequence: str, word: str) -> int:
        ans = 0
        sub = word
        while sequence.find(sub) != -1:
            ans += 1
            sub += word
        return ans

提交代码评测得到:耗时32ms,占用内存14.1MB。

当前最优的代码实现耗时20ms,但是看了一下算法思路上是完全相同的,因此这里就不多做展开了。

2. 题目二

给出题目二的试题链接如下:

1. 解题思路

这一题同样的,如果放在一般的情况,那么要考虑下面一些特殊情况:

  1. a刚好为list1的开头;
  2. b刚好为list2的结尾;

但是,题目给出的限制条件直接排除了这些特殊情况出现的可能性,因此,我们要做的就只剩下找到开始节点和结束节点,然后把list2加入进去就行了。

2. 代码实现

给出python代码实现如下:

class Solution:
    def mergeInBetween(self, list1: ListNode, a: int, b: int, list2: ListNode) -> ListNode:
        p0 = list1
        counter = 0
        while p0:
            if counter == a-1:
                p_st = p0
            elif counter == b+1:
                p_ed = p0
                break
            p0 = p0.next
            counter += 1
            
        p_st.next = list2
        p0 = list2
        while p0.next:
            p0 = p0.next
        p0.next = p_ed
        return list1

提交代码评测得到:耗时460ms,占用内存20.1MB。

当前最优的代码实现耗时440ms,同样的,考察其代码实现之后发现,思路上两者是完全一致的,因此就不多做展开了。

3. 题目三

给出题目三的试题链接如下:

1. 解题思路

这一题同样感觉没啥东西,就是在一个数组中准确的进行定位然后进行数值删除和插入即可,用python的list类的固有函数进行实现就行了。

2. 代码实现

给出python代码实现如下:

class FrontMiddleBackQueue:

    def __init__(self):
        self.q = []
        self.n = 0

    def pushFront(self, val: int) -> None:
        self.q.insert(0, val)
        self.n += 1

    def pushMiddle(self, val: int) -> None:
        self.q.insert(self.n // 2, val)
        self.n += 1

    def pushBack(self, val: int) -> None:
        self.q.append(val)
        self.n += 1

    def popFront(self) -> int:
        if self.n > 0:
            self.n -= 1
            return self.q.pop(0)
        else:
            return -1

    def popMiddle(self) -> int:
        if self.n > 0:
            self.n -= 1
            return self.q.pop(self.n // 2)
        else:
            return -1

    def popBack(self) -> int:
        if self.n > 0:
            self.n -= 1
            return self.q.pop()
        else:
            return -1

提交代码评测得到:耗时72ms,占用内存14.8MB。

当前最优的代码实现耗时460ms,看了一下,他们并没有使用insert内置方法,但是看了一下题目,好像确实没有说不能够使用insert内置方法,就比较疑惑。。。

4. 题目四

给出题目四的试题链接如下:

1. 解题思路

这一题讲道理如果把时间卡的比较紧的话还是挺折腾的,反正我是一下子没有想到什么特别巧妙的方法。

但是,由于给的数组长度不长于1000,因此,当算法复杂度是 O ( N 2 ) O(N^2) O(N2)时,整体耗时应该也还是在允许范围内,就可以尝试一下暴力算法。

我们的暴力求解思路其实也蛮简单的,就是对每一个元素,假设他是保留下来的山峰的情况下,看他左边和右边最多能够保留下多少个元素,最后取出最大的这个就是我们最后的选法,用总的元素个数减去保留的元素个数,就是最小需要删除的元素数目。

而考虑每个元素左侧能够保留的最大元素个数时(记作lcount[i]),只要找到它左侧所有比他更小的元素,就会有lcount[i] = min(lcount[j]+1, lcount[i])即可,这样我们就能在 O ( N 2 ) O(N^2) O(N2)时间复杂度范围内获取每一个元素作为山峰时左侧可以保留的最大元素个数。

同理我们也可以获得每一个元素作为山峰时右侧可以保留的最大元素个数。

至此,问题即求解完成。

2. 代码实现

给出python代码实现如下:

class Solution:
    def minimumMountainRemovals(self, nums: List[int]) -> int:
        n = len(nums)
        lcount = [0 for _ in range(n)]
        for i in range(1, n):
            for j in range(i):
                if nums[i] > nums[j]:
                    lcount[i] = max(lcount[i], lcount[j] + 1)
                    
        rcount = [0 for _ in range(n)]
        for i in range(n-2, -1, -1):
            for j in range(n-1, i, -1):
                if nums[i] > nums[j]:
                    rcount[i] = max(rcount[i], rcount[j] + 1)
        
        ans = n
        for i in range(n):
            if lcount[i] != 0 and rcount[i] != 0:
                ans = min(ans, n-(1+lcount[i]+rcount[i]))
        return ans

提交代码评测得到:耗时3896ms,占用内存14.6MB。

当前最优的代码实现耗时3476ms,但是看了一下,两者的算法思路是完全相同的,因此这里就不多做展开了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值