代码随想录算法训练营|Day 11
Day 11
第五章 栈与队列part02
150. 逆波兰表达式求值
本题不难,但第一次做的话,会很难想到,所以先看视频,了解思路再去做题
题目链接/文章讲解/视频讲解:https://programmercarl.com/0150.逆波兰表达式求值.html
遇见数字加入到栈里,遇到操作符开始从栈里弹出(弹出两个元素进行运算)
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:
def evalRPN(self, tokens: List[str]) -> int:
stack = []
ops = {'+':add, '-':sub, '*':mul, '/':div}
for item in tokens:
if item in {'+','-','*','/'}:
ele1 = stack.pop()
ele2 = stack.pop()
stack.append(ops[item](ele2,ele1))
else:
stack.append(int(item))
return stack.pop()
239. 滑动窗口最大值 (有点难度,可能代码写不出来,但一刷至少需要理解思路)
之前讲的都是栈的应用,这次该是队列的应用了。
本题算比较有难度的,需要自己去构造单调队列,建议先看视频来理解。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0239.滑动窗口最大值.html
滑动窗口移动一个位置→队列pop出一个元素,再push进一个元素
单调队列:维护队列里单调递增或单调递减
维护出口处是最大值
push进的元素比前面的大,把前面的弹出,直到前面元素没有我这个加入的元素大为止



from collections import deque
class MyQueue:
def __init__(self):
self.que = deque()
def pop(self, value):
if self.que and value == self.que[0]:
self.que.popleft()
def push(self, value):
while self.que and value > self.que[-1]:
self.que.pop()
self.que.append(value)
def front(self):
return self.que[0]
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
que = MyQueue()
res = []
for i in range(k):
que.push(nums[i])
res.append(que.front())
for i in range(k, len(nums)):
que.pop(nums[i-k])
que.push(nums[i])
res.append(que.front())
return res
解法二:直接使用单调队列
from collections import deque
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
max_list = [] # 结果集合
kept_nums = deque() # 单调队列
for i in range(len(nums)):
update_kept_nums(kept_nums, nums[i]) # 右侧新元素加入
if i >= k and nums[i - k] == kept_nums[0]: # 左侧旧元素如果等于单调队列头元素,需要移除头元素
kept_nums.popleft()
if i >= k - 1:
max_list.append(kept_nums[0])
return max_list
def update_kept_nums(kept_nums, num): # num 是新加入的元素
# 所有小于新元素的队列尾部元素,在新元素出现后,都是没有价值的,都需要被移除
while kept_nums and num > kept_nums[-1]:
kept_nums.pop()
kept_nums.append(num)
347.前 K 个高频元素 (有点难度,可能代码写不出来,一刷至少需要理解思路)
大/小顶堆的应用, 在C++中就是优先级队列
本题是 大数据中取前k值 的经典思路,了解想法之后,不算难。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0347.前K个高频元素.html
小顶堆,这个堆只维护k个元素



#时间复杂度:O(nlogk)
#空间复杂度:O(n)
import heapq
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
#要统计元素出现频率
map_ = {} #nums[i]:对应出现的次数
for i in range(len(nums)):
map_[nums[i]] = map_.get(nums[i], 0) + 1
#对频率排序
#定义一个小顶堆,大小为k
pri_que = [] #小顶堆
#用固定大小为k的小顶堆,扫描所有频率的数值
for key, freq in map_.items():
heapq.heappush(pri_que, (freq, key))
if len(pri_que) > k: #如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
heapq.heappop(pri_que)
#找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组
result = [0] * k
for i in range(k-1, -1, -1):
result[i] = heapq.heappop(pri_que)[1]
return result
总结
栈与队列做一个总结吧,加油

浙公网安备 33010602011771号