第二专题 堆栈(stack)和队列(Queue)
前导知识点:
- Stack - First In Last Out(FILO)先进后出
所用到的数据结构:Array or Linked List
- Queue-First In First Out(FIFO)先进后出
所用到的数据结构:Array or Doubly Linked List
1. leetcode20. 有效的括号(easy)
class Solution:
def isValid(self, s: str) -> bool:
partner = {')':'(',']':'[','}':'{'}
stack = list()
for i in s:
if i in partner:
if not stack or stack.pop() != partner[i]:
return False
else:
stack.append(i)
return not stack
2. leetcode225. 用队列实现栈
解题思路:使用双队列,使用python语言求解的话,可以使用列表数据结构,因此为了满足队列的特性我们仅使用列表的append和pop(0)方法。
思路比较简单:我们仅需要维护一个queue1,在添加一个元素时,我们只需要将其添加到queue2中,然后通过将queue1中所有的数出队列到queue2中,后面通过交换queue1和queue2的指向就可。插入的时间复杂度为O(n),其余操作的时间复杂度为O(1)
class MyStack:
def __init__(self):
"""
Initialize your data structure here.
"""
self.queue1 = []
self.queue2 = []
def push(self, x: int) -> None:
"""
Push element x onto stack.
"""
self.queue2.append(x)
while self.queue1:
self.queue2.append(self.queue1.pop(0))
self.queue1,self.queue2 = self.queue2,self.queue1
def pop(self) -> int:
"""
Removes the element on top of the stack and returns that element.
"""
return self.queue1.pop(0)
def top(self) -> int:
"""
Get the top element.
"""
return self.queue1[0]
def empty(self) -> bool:
"""
Returns whether the stack is empty.
"""
return not self.queue1
3. leetcode232. 用栈实现队列
题目分析:
栈为先入后出,而队列是先进先出。要使用栈实现先入先出的队列的话,可以预定义两个栈,一个作为输入栈,一个作为输出栈。当压入数据时,则直接放在输入栈中。当使用pop, peek, empty输出时,则主要对输出栈进行操作:
class MyQueue:
def __init__(self):
"""
Initialize your data structure here.
"""
self.input_stack = []
self.output_stack = []
def push(self, x: int) -> None:
"""
Push element x to the back of queue.
"""
self.input_stack.append(x)
def pop(self) -> int:
"""
Removes the element from in front of queue and returns that element.
"""
if self.output_stack:
return self.output_stack.pop()
else:
while self.input_stack:
self.output_stack.append(self.input_stack.pop())
return self.output_stack.pop()
def peek(self) -> int:
"""
Get the front element.
"""
if self.output_stack:
return self.output_stack[-1]
else:
while self.input_stack:
self.output_stack.append(self.input_stack.pop())
return self.output_stack[-1]
def empty(self) -> bool:
"""
Returns whether the queue is empty.
"""
return not self.output_stack and not self.input_stack
优先队列(PriorityQueue)
- 正常入、按照优先级出
优先队列的实现机制:
Heap(Binary, Binomial, Fibonacci)
Binary Search Tree
4.从topK问题学习堆栈的思想以及python标准库方式与python实现笔记
5. 239. 滑动窗口最大值
方法1 使用优先队列——堆
维护一个大小为K的大根堆,对大根堆,每一次滑动窗口,即向堆中删除和加入元素,维护堆的结构的时间复杂度为O(logk),遍历的时间复杂度为O(n),因此总的时间复杂度为O(n*logk)
import heapq
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
n = len(nums)
# 初始化一个堆q
q = [(-nums[i],i) for i in range(k)]
heapq.heapify(q)
res = [-q[0][0]]
for i in range(k,n):
heapq.heappush(q,(-nums[i], i))
while q[0][1]<= i-k:
heapq.heappop(q)
res.append(-q[0][0])
return res
方法2. 使用单调队列
维护一个堆,显然还有一些冗余在里面,因此我们可以维护一个队列,让队列的前面始终为当前滑动窗口最大的数字。每次我们比较接着进入队列的数据,如果比队列最前面的数都大,那么直接让队列为空,并将该数入队列。为了随时确定每一次操作,当前最大的数都还存在于滑动窗口中,维护队列时仅保存索引到队列中,方便进行判断。
from collections import deque
class Solution:
def maxSlidingWindow(self, nums, k):
n = len(nums)
q = deque()
for i in range(k): # 初始化一个双端队列
while q and nums[q[-1]] <= nums[i]:
q.pop()
q.append(i)
res = [nums[q[0]]]
for i in range(k,n):
while q and nums[q[-1]] < nums[i]:
q.pop()
q.append(i)
while q[0] <= i-k:
q.popleft()
res.append(nums[q[0]])
return res