栈与队列
栈的基础知识
栈是一种后进先出(LIFO)的数据结构,只允许在栈顶进行插入和删除操作。栈的基本操作包括:
-
push(x):将元素x压入栈顶。 -
pop():弹出栈顶元素并返回。 -
peek()或top():返回栈顶元素但不删除。 -
isEmpty():判断栈是否为空。
栈的典型应用场景包括:
-
函数调用栈:递归或函数调用时的上下文存储。
-
括号匹配:检查表达式中的括号是否成对出现。
-
表达式求值:中缀表达式转后缀表达式并计算。
-
深度优先搜索(DFS):用于模拟递归或回溯。
队列的基础知识
队列是一种先进先出(FIFO)的数据结构,允许在队尾插入元素,在队首删除元素。队列的基本操作包括:
-
enqueue(x):将元素x插入队尾。 -
dequeue():删除队首元素并返回。 -
front():返回队首元素但不删除。 -
isEmpty():判断队列是否为空。
队列的典型应用场景包括:
-
广度优先搜索(BFS):按层次遍历树或图。
-
任务调度:处理按顺序到达的任务。
-
滑动窗口问题:如求滑动窗口的最大值或最小值。
双端队列(Deque)
双端队列是一种允许在两端进行插入和删除操作的数据结构。结合了栈和队列的特性,常见操作包括:
-
addFirst(x):在队首插入元素。 -
addLast(x):在队尾插入元素。 -
removeFirst():删除队首元素。 -
removeLast():删除队尾元素。
双端队列的应用场景包括:
-
滑动窗口问题:如LeetCode中的"239. 滑动窗口最大值"。
-
实现栈或队列:通过限制操作端模拟栈或队列。
232.用栈实现队列
题目链接232. 用栈实现队列 - 力扣(LeetCode)
思路

用两个栈去实现一个队列,一个是in,一个是out,但是需要注意,必须把in里面的全部放到out,不然出来的顺序就会乱。
在push数据的时候,只要数据放进输入栈就好,但在pop的时候,操作就复杂一些,输出栈如果为空,就把进栈数据全部导入进来(注意是全部导入),再从出栈弹出数据,如果输出栈不为空,则直接从出栈弹出数据就可以了。
最后如何判断队列为空呢?如果进栈和出栈都为空的话,说明模拟的队列为空了。
写题
1.self.stack_out,有时候要把self写漏
2.还有 ans=self.pop(),我刚刚把他写成了ans=self.stack_out.pop()然后报错,说是为空什么的
-
self.stack_out.pop():只操作出队栈 ,不管入队栈有没有数据,不会自动倒数据 -
self.pop():完整的出队逻辑 ,会自动判断、自动把stack_in倒入stack_out,是安全、完整的出队方法

python
class MyQueue:
def __init__(self):
self.stack_in=[]
self.stack_out=[]
def push(self, x: int) -> None:
self.stack_in.append(x)
def pop(self) -> int:
if self.empty(): # 如果队列为空,直接返回None
return None
if self.stack_out: # 如果出队栈有元素,直接弹出栈顶(队首)
return self.stack_out.pop()
else: # 如果出队栈为空,将入队栈所有元素倒入出队栈
for i in range(len(self.stack_in)):
self.stack_out.append(self.stack_in.pop())
return self.stack_out.pop() # 弹出出队栈顶,即队首元素
def peek(self) -> int:
ans=self.pop() # 先调用pop临时取出队首元素
self.stack_out.append(ans) # 将取出的元素放回出队栈,不删除
return ans # 返回队首元素
def empty(self) -> bool:
return not(self.stack_in or self.stack_out)
# Your MyQueue object will be instantiated and called as such:
# obj = MyQueue()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.peek()
# param_4 = obj.empty()
225. 用队列实现栈
题目链接225. 用队列实现栈 - 力扣(LeetCode)
思路

把前面size-1个元素弹出来,加到队列的后面,再把交换顺序之后的第一个取出来。
写题
这里用了一个队列,感觉这个popleft()挺好用的

python
from collections import deque # 必须导入才能用deque
class MyStack:
def __init__(self):
self.que=deque()
def push(self, x: int) -> None:
self.que.append(x)
def pop(self) -> int:
if self.empty(): # 如果栈为空,返回None
return None
for i in range(len(self.que)-1): # 把除最后一个外的所有元素,依次移到队列尾部
self.que.append(self.que.popleft())
return self.que.popleft() # 弹出此时队首元素(原栈顶)
def top(self) -> int:
if self.empty(): # 如果栈为空,返回None
return None
for i in range(len(self.que)-1): # 把除最后一个外的所有元素,依次移到队列尾部
self.que.append(self.que.popleft())
temp=self.que.popleft() # 取出队首(栈顶)暂存
self.que.append(temp) # 再放回队列,保持结构不变
return temp # 返回栈顶元素
def empty(self) -> bool:
return not self.que
# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()
20. 有效的括号
思路
虽然知道要用到栈,但是代码具体怎么写,括号具体怎么判断我还是不会
遍历,比如遇到'['就把与他匹配的']'加入栈中,下一次遇到方括号,判断判断是否有匹配的方括号,有就消除,没有就return False
最后再判断栈是否为空,为空,说明全都匹配了;不为空,说明还有括号没有匹配。
如果输入的括号个数是奇数,那一定不匹配
写题

python
class Solution:
def isValid(self, s: str) -> bool:
stack=[]
if len(s)%2==1:
return False
for items in s:
if items =='[':
stack.append(']')
elif items == '(':
stack.append(')')
elif items =='{':
stack.append('}')
# 栈为空 或 栈顶符号与当前右括号不匹配 → 括号不合法
elif not stack or stack[-1]!=items:
return False
# 括号匹配成功 → 弹出栈顶的匹配符号
else:
stack.pop()
# 遍历结束后栈为空 → 所有括号都匹配,返回True;否则返回False
return True if not stack else False
1047. 删除字符串中的所有相邻重复项
题目链接 1047. 删除字符串中的所有相邻重复项 - 力扣(LeetCode)
思路
字母不在栈中,或者栈最后一个不和输入字母匹配,都应该加入栈中
其余情况,把字母弹出去。
写题
通过了一部分的测试样例

python
class Solution:
def removeDuplicates(self, s: str) -> str:
stack=[]
for i in s:
if i not in stack:
stack.append(i)
elif not stack and stack[-1]!=i:
continue
else:
stack.pop()
return ''.join(stack)
我运行了一下没有通过的测试用例,发现是加入元素时判断条件不对,反而把一个元素弹出。
然后我发现其实字母不在栈里面或者
是栈最后一个元素不和进入的字母匹配
都应该加入栈中

python
class Solution:
def removeDuplicates(self, s: str) -> str:
stack=[]
for i in s:
if i not in stack or stack[-1]!=i:
stack.append(i)
else:
stack.pop()
return ''.join(stack)