首页 > 其他分享 >day11 栈与队列

day11 栈与队列

时间:2024-07-27 15:06:52浏览次数:9  
标签:op1 op2 队列 self pop int val day11

任务

150. 逆波兰表达式求值

思路

用栈保存操作数,遇到操作符,将操作数弹出并处理。注意除法的逻辑

class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        s = []
        from operator import add, sub, mul
        op_dic = {'+':add,'-':sub }
        for i in range(len(tokens)):
            if tokens[i] not in {'+','-','*','/'}:
                s.append(int(tokens[i]))
            elif tokens[i] == '+':
                op2 = s.pop()
                op1 = s.pop()
                s.append(add(op1,op2))
            elif tokens[i] == '-':
                op2 = s.pop()
                op1 = s.pop()
                s.append(sub(op1,op2))
            elif tokens[i] == '*':
                op2 = s.pop()
                op1 = s.pop()
                s.append(mul(op1,op2))
            elif tokens[i] == '/':
                op2 = s.pop()
                op1 = s.pop()
                val =  op1//op2 if op1 * op2 > 0 else -(abs(op1) // abs(op2))# 向0取整
                s.append(val)
        return s[0]

239. 滑动窗口最大值

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值

思路

额外维护这样一个滑动窗口(双端队列结构),因此该结构需要保证:某一时刻,双端队列中头结点的值为最大值。
逻辑上,双端队列维护的是什么信息呢?

  1. 如果依次扩充窗口,谁会成为最大值的信息。
  2. 如果不再扩充而是依次缩减滑动窗口,谁会成为最大值的信息。

当数组中的窗口往右扩时,为了维护上述结构,需要队列中将它之前比它小的数都移除出去。这个是比较好想到的。
更深入的思考:为什么新的数进来后可以让之前比它小的数(或者相等的数)弹出呢?因为这个弹出的数再也不可能成为最大值了,我的新数比你大还比你晚过期,那么就不需要你这个旧的小值了。也即是,滑动窗口实际上维护的信息是两个维度,数字越新越大越优先。按照上述逻辑,实际上,双端队列每一时刻都是单调递减的。那么缩减呢?只有当前要缩减的元素没有在之前扩充时处理过,才缩减,否则已经被处理过了。
完整的算法如下

  • 扩充:只要比当前要入队的数小,则从窗口中弹出
  • 缩减:如果和头节点的数一样(旧的最大值),则弹出。否则当前需要处理的数就是又旧又不是之前的最大值的数,扩充时已经被处理过了。
  • 最大值:队首元素
class MyWindow:
    def __init__(self):
        self.queue = deque()
    def push(self,val):
        while(self.queue and val > self.queue[-1]): #只要比当前要入队的数小,则从窗口中弹出
            self.queue.pop()
        self.queue.append(val) #将当前值放入滑动窗口
    
    def pop(self,val):
        if(self.queue and self.queue[0] == val):
            self.queue.popleft()

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

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        res = []
        window = MyWindow()
        for i in range(k):
            window.push(nums[i]) 
        res.append(window.getMaxValue()) 
        size = len(nums)
        for i in range(k,size):
            window.pop(nums[i-k])
            window.push(nums[i])
            maxV = window.getMaxValue()
            res.append(maxV)
        return res

347.前 K 个高频元素

思路

堆(优先级队列)
这里只考虑优先级队列的功能,暂时不考虑实现(上滤下滤等),以小顶堆为例,即在加入和删除元素的过程中,堆顶元素保持最小值。
我们用dic来统计频率,然后利用小顶堆依次添加,达到k个后,再依次添加和弹出最小元素,保证最大的k个元素均在小顶堆中,即可完成。

class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        import heapq
        import collections
        dic = collections.defaultdict(int) 
        for i in range(len(nums)):
            dic[nums[i]] += 1
        
        pq = [] #默认小顶堆
        for key,v in dic.items():
            heapq.heappush(pq,(v,key))
            if len(pq) > k:       #后续每次新加入元素,满足堆的结构后,弹出堆顶元素(最小值)
                heapq.heappop(pq)
        
        #此时pq中的元素为最大的k个元素,pq的堆顶为这k个内最小的元素
        res = [0]*k
        
        for i in range(k-1,-1,-1): #逆序赋值,保证次数单调递减,val的次数越多的越靠前
            val = heapq.heappop(pq)[1]
            res[i] = val
        return res

心得体会

复习了栈的应用,学习了滑动窗口(双端队列)和优先级队列。注意后两种结构的思路和应用。

  • 栈的应用 相邻项之间的消除
  • 滑动窗口 与之前的数组中那道题不同,本题是自定义了一种特殊功能的数据结构,保证了可以很快取出极值,并随着窗口的滑动,这个性质保持不变。
  • 优先级队列 同样利用元素的插入删除,堆结构性质的一致性,保证栈顶为极值,解决topK问题。

标签:op1,op2,队列,self,pop,int,val,day11
From: https://www.cnblogs.com/haohaoscnblogs/p/18326972

相关文章

  • 19.延迟队列优化
    问题前面所讲的延迟队列有一个不足之处,比如现在有一个需求需要延迟半个小时的消息,那么就只有添加一个新的队列。那就意味着,每新增一个不同时间需求,就会新创建一个队列。解决方案应该讲消息的时间不要跟队列绑定,应该交给消息的生产者,由发送消息来指定延迟时间。这样就可以定......
  • 秒杀优化-基于阻塞队列实现秒杀优化
    秒杀优化VoucherOrderServiceImpl修改下单动作,现在我们去下单时,是通过lua表达式去原子执行判断逻辑,如果判断我出来不为0,则要么是库存不足,要么是重复下单,返回错误信息,如果是0,则把下单的逻辑保存到队列中去,然后异步执行@Slf4j@ServicepublicclassVoucherOrderServiceImplex......
  • 单调栈和单调队列
    单调栈和单调队列P5788#include<bits/stdc++.h>usingnamespacestd;constintN=3e6+5;intn,a[N],ans[N],top,stk[N];intmain(){ scanf("%d",&n); for(inti=1;i<=n;++i){ scanf("%d",&a[i]); while(top>0&&a[stk[......
  • 直播平台搭建,需要实现的核心要素之队列
    直播平台搭建,需要实现的核心要素之队列队列的实现在直播平台搭建中,队列的实现分为队列的定义和操作,如前所述,队列是元素的有序集合,添加操作发生在其尾部,移除操作则发生在头部。队列的操作顺序是先进先出(FIFO),它支持以下操作。Queue():创建一个空队列。它不需要参数,且会......
  • DAY10 栈与队列part01
     理论基础文章讲解:https://programmercarl.com/%E6%A0%88%E4%B8%8E%E9%98%9F%E5%88%97%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html232.用栈实现队列 注意为什么要用两个栈题目链接/文章讲解/视频讲解:https://programmercarl.com/0232.%E7%94%A8%E6%A0%88%E5%AE%9E%E7%8E%......
  • C++优先队列 涵盖各种易错,技巧,应用和原理(附手写代码)
    当然也可以不看==> 阅读我的文章前请务必先阅读此文章! 都是废话这个文章里有视频,不知道为什么一点开文章就会播放,可以先翻到最后暂停一下再回来看目录阅读文章须知引言优先队列的概念优先队列的创建优先队列的操作*还有一些不常用的:优先队列的技巧如果类型是结构......
  • 软考-软件设计师(3)-数据结构与算法:树、图、队列、查找算法、排序算法、霍夫曼编码/
    场景软考-软件设计师-数据结构与算法模块高频考点整理。以下为高频考点、知识点汇总,不代表该模块所有知识点覆盖,请以官方教程提纲为准。注:博客:霸道流氓气质-CSDN博客实现知识点树:节点的度、树的度、深度、高度、满二叉树、完全二叉树、平衡二叉树、B树、二叉排序树节点......
  • 代码随想录day10 || 232 栈实现队列, 225 队列实现栈,20 删除有效括号,1047 删除字符串相
    232实现队列//go本身并不支持原生的栈和队列结构,都是通过切片实现的//leetcodesubmitregionbegin(Prohibitmodificationanddeletion)typeMyQueuestruct{ Data[]int Sizeint}funcConstructor()MyQueue{ returnMyQueue{}}func(this*MyQueue)Push(......
  • Day10 栈和队列Part1
    任务232.用栈实现队列请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty)思路算是一个模拟类的题目,用py中,用列表加上限制条件表示栈(只能用pop表示对栈顶元素出栈处理)push:用stackIn保存入队元素pop:出队时,分三种情况,如果队列......
  • 算法入门篇(四)之栈和队列
    目录一、顺序栈、链栈1、顺序栈1.定义与存储结构2.特点3.适用场景2、链栈1.定义与存储结构2.特点3.适用场景3、总结二、顺序队列、链式队列1、顺序队列1.定义与存储结构2.特点3.循环队列4.适用场景2、链式队列1.定义与存储结构2.特点3.适用......