代码随想录 day10:第五章 栈与队列part02

150. 逆波兰表达式求值

在这里插入图片描述
思路:

  • 栈与递归之间在某种程度上是可以转换的。
  • 逆波兰表达式相当于是二叉树中的后序遍历,可以把运算符作为中间节点,按照后序遍历的规则画出一个二叉树。
  • 注意负数取整是向零取整方式,,也就是取大。

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

class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        
        op_map={'+':add,'-':sub,'*':mul,'/':div}

        stack=[]
        for i in tokens:
            if i not in op_map:
                stack.append(int(i))
            else:
                op2=stack.pop()#先弹出来的是第二个数
                op1=stack.pop()#然后弹出来的是第一个数
                stack.append(op_map[i](op1,op2))
        return stack.pop()

239. 滑动窗口最大值

  • 队列的应用,构造单调队列
    在这里插入图片描述
    思路:
  • 使用单调队列的经典题目。
  • 如果用一个大顶堆(优先级队列)来存放这个窗口里的k个数字,这样就可以知道最大的最大值是多少了, 但是这个窗口是移动的,而大顶堆每次只能弹出最大值,无法移除其他数值,这样就造成大顶堆维护的不是滑动窗口里面的数值了。所以不能用大顶堆。
  • 需要一个队列,使得放进去窗口里的元素,随着窗口的移动,队列也一进一出,每次移动之后,队列告诉我们里面的最大值是什么。
  • 构造大小为k的单调队列,pop处最大,先进先出,故越前面越大;
  • 或者构造大小为k的单调栈,pop处最大,先进后出,故越前面越小
  • 每次移动窗口的时候,调用que.pop(滑动窗口中移除元素的数值),que.push(滑动窗口添加元素的数值),然后que.front()就返回我们要的最大值。
  • 没有必要维护窗口里的所有元素,只需要维护有可能成为窗口里最大值的元素就可以了,同时保证队列里的元素数值是由大到小的。
  • pop和push的操作规则:
  • pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
  • push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止
  • queue在没有指定容器的情况下,deque就是默认底层容器。
from collections import deque

class Mydeque:
    def __init__(self):
        self.queue=deque()#使用deque实现单调队列
    
    #每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。
    #同时pop之前判断队列当前是否为空。
    def pop(self,value):
        if self.queue and value==self.queue[0]:
            self.queue.popleft()
    
    #如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。
    #这样就保持了队列里的数值是单调从大到小的了。
    def push(self,value):
        while self.queue and value>self.queue[-1]:#队列不为空且push元素大于队列最小元素也就是队尾元素时,就一直弹出
            self.queue.pop()
        self.queue.append(value)

    def front(self):
        return self.queue[0]#返回队首元素


class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        que=Mydeque()
        result=[]
        for i in range(k):#先将前k的元素放进队列
            que.push(nums[i])
        result.append(que.front())#result 记录前k的元素的最大值

        for i in range(k,len(nums)):
            que.pop(nums[i-k])#滑动窗口移除最前面元素
            que.push(nums[i])
            result.append(que.front())

        return result

347.前 K 个高频元素

  • 大/小顶堆的应用, 在C++中就是优先级队列
  • 本题是 大数据中取前k值 的经典思路
    在这里插入图片描述
class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        from collections import defaultdict
        table=defaultdict(int)
        for i in nums:
            table[i]+=1
        # print(sorted(table)[-k:])
        # 更改字典,key为出现次数,value为相应的数字的集合
        index_dict=defaultdict(list)
        for i in table:
            index_dict[table[i]].append(i)#键名为出现次数,键值为相应数字
        #排序
        key=list(index_dict.keys())#出现次数集合
        key.sort()#从小到大排序
        result=[]
        cnt=0
        #获取前K项
        while key and cnt!=k:
            result+=index_dict[key[-1]]#最大的次数(可能有多个数值)
            cnt+=len(index_dict[key[-1]])#计算相同次数的数出现了几次
            key.pop()
        return result
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值