代码随想录算法训练营DAY11|Leetcode 150、239、347

文章链接: 代码随想录
150. 逆波兰表达式求值 + 239.滑动窗口最大值 + 347. 前K个高频元素
学习到了单调队列和大小顶堆的知识,有点难

150. 逆波兰表达式求值

状态:有思路但不太确定,看视频讲解后,自己写代码

思路:使用栈:遇到数字就入栈,遇到运算符,则取出栈顶前两个元素进行运算,并将结果放回栈中,以此类推

总结:

1. 思路比较明晰,但对比示例代码后,觉得自己写代码方面的优化能力有待提高:使用python的operator模块。

摘自笔记:Python 什么情况下应该使用Python内置的 ‘operator’ 模块|极客笔记

     在什么情况下使用Python内置的 ‘operator’ 模块?

  1. 需要在运行时动态执行不同的运算符操作。
  2. 需要对容器对象(例如列表、元组和字典)中的元素进行比较或排序操作。
  3. 需要对自定义的对象进行比较操作,以便能够正确排序或比较它们。

     通过使用 ‘operator’ 模块,我们可以避免编写大量的条件语句来处理不同的运算符操作,从而使代码更加简洁、清晰,并提高运行效率。

# 示例代码(来自代码随想录)
from operator import add, sub, mul

def div(x, y):
    # 使用整数除法的向零取整方式
    return int(x / y) if x * y > 0 else -(abs(x) // abs(y))

class Solution(object):
    op_map = {'+': add, '-': sub, '*': mul, '/': div}
    
    def evalRPN(self, tokens: List[str]) -> int:
        stack = []
        for token in tokens:
            if token not in {'+', '-', '*', '/'}:
                stack.append(int(token))
            else:
                op2 = stack.pop()
                op1 = stack.pop()
                stack.append(self.op_map[token](op1, op2))  # 第一个出来的在运算符后面
        return stack.pop()

2. 题目要求“整数除法只保留整数部分”,而python中的 '/' 不是整除,‘//’是floor除法(向下舍入),因此要对除法做特殊处理(可以参考上述的示例代码),我自己的代码中用的是强制int转换。

3. 要注意入栈时,数据类型从str --> int的转换

4. 时间复杂度: O(n),空间复杂度: O(n)

class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        s = []
        for i in tokens:
            if i == '+' or i =='-' or i =='*' or i == '/':
                num1 = s.pop()
                num2 = s.pop()
                if i == '+':
                    s.append(num2 + num1)
                if i =='-':
                    s.append(num2 - num1)
                if i == '*':
                    s.append(num2 * num1)
                if i == '/':
                    s.append(int(num2 / num1))
            else:
                s.append(int(i))

        return s[-1]

239. 滑动窗口最大值

状态:想到要用队列,但是对于具体用哪种队列,怎么写代码没有思路,也没有意识到找最大值的难度。看完视频讲解和示例代码后,自己学着写代码

思路:设计一个单调队列,具有pop, push和getMaxvalue功能。该队列只需要维护有可能成为窗口里最大值的元素就可以了,同时保证队列里的元素数值是由大到小的。

摘自代码随想录:

设计单调队列的时候,pop,和push操作要保持如下规则:

  1. pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
  2. push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止

保持如上规则,每次窗口移动的时候,只要问que.front()就可以返回当前窗口的最大值。

总结:

1. 学习了单调队列的知识,以及为什么不能用优先级队列的原因

2. 在push(value)中,直接将小于value的入口元素全部弹出,队列里保证只留有可能成为窗口最大值的元素

3. 在主函数遍历数组nums[k, len(nums)]时的逻辑是:先pop第 j - k个元素(即出口元素),再push元素,之后记录窗口最大值

4. 时间复杂度: O(n), 空间复杂度: O(k)

from collections import deque

class MyQue:
    def __init__(self):
        self.queue = deque()
    
    def pop(self, val: int):
        if self.queue and val == self.queue[0]:
            self.queue.popleft()

    def push(self, val: int):
        while self.queue and val > self.queue[-1]:
            self.queue.pop()
        self.queue.append(val)

    def getMaxValue(self):
        return self.queue[0]


class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        que = MyQue()
        result = []
        for i in range(k):
            que.push(nums[i])
        result.append(que.getMaxValue())

        for j in range(k, len(nums)):
            que.pop(nums[j-k])
            que.push(nums[j])
            result.append(que.getMaxValue())
        return result

347.前 K 个高频元素

状态:想到用字典记录数字出现频率,但不知道如何让用队列解决取前k个高频元素的问题。看完视频讲解和示例代码后,自己学着写代码

思路:分3步:1)用字典记录频率;2)使用小顶堆进行排序;3)返回前k个高频元素

总结:

1. 初步了解优先级队列(小顶堆)的知识:小顶堆每次将最小的元素弹出,最后小顶堆里积累的才是前k个最大元素

2. python小顶堆可用heapq模块实现,heappush和heappop分别用来存入和弹出元素;注意存入堆时要按照(freq, key)存入,即按照freq进行排序

3. leetcode上不要求从大到小返回前k个元素,但返回的是key, 即heapq.heappop(que)[1]

4. 时间复杂度: O(nlogk), 空间复杂度: O(n)

import heapq
class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        dict_ = {}
        for i in range(len(nums)):
            dict_[nums[i]] = dict_.get(nums[i], 0) + 1

        que = []

        for key, freq in dict_.items():
            heapq.heappush(que, (freq, key)) # 按照频率大小排序
            if len(que) > k:
                heapq.heappop(que)

        # 任意顺序返回答案
        res = []
        for i in range(k):
            res.append(heapq.heappop(que)[1])
        return res

        

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值