目录
栈和队列的相互实现
232 用栈实现队列
- easy
- 题目描述
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
- 解题思路
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():
return None
if self.stack_out:
return self.stack_out.pop()
else:
# 一次性把stack_in中的元素转移到stack_out中来
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:
# 首先用pop()函数移除元素,然后再加回来
temp = self.pop()
self.stack_out.append(temp)
return temp
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 用队列实现栈
- easy
- 题目描述
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
- 解题思路
class MyStack:
def __init__(self):
# 第二个队列用于保存第一个pop出来的元素
self.queue_in = deque()
self.queue_out = deque()
def push(self, x: int) -> None:
self.queue_in.append(x)
def pop(self) -> int:
if self.empty():
return None
# 先把除栈顶外其余元素送入out中
for i in range(len(self.queue_in) - 1):
self.queue_out.append(self.queue_in.popleft())
ans = self.queue_in.popleft()
# 这里互换以后,queue_out是空,queue_in是pop后的结果
self.queue_in, self.queue_out = self.queue_out, self.queue_in
return ans
def top(self) -> int:
if self.empty():
return None
return self.queue_in[-1]
def empty(self) -> bool:
if len(self.queue_in) == 0:
return True
return False
# 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 有效的括号
- easy
- 题目描述
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
- 解题思路
class Solution:
def isValid(self, s: str) -> bool:
# 遇到左括号就压栈,遇到右括号就弹栈
stack = []
for item in s:
if item == "(":
stack.append(")")
elif item == "{":
stack.append("}")
elif item == "[":
stack.append("]")
# 左/右括号多了或者括号类型不能匹配
elif not stack or item != stack[-1]:
return False
else:
stack.pop()
return True if not stack else False
1047 删除字符串中的所有相邻重复项
- easy
- 题目描述
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
- 解题思路
class Solution:
def removeDuplicates(self, s: str) -> str:
# 栈入栈和出栈相互抵消
stack = []
for item in s:
if not stack:
stack.append(item)
elif item == stack[-1]:
stack.pop()
else:
stack.append(item)
return "".join(stack)
150 逆波兰表达式求值
- medium
- 题目描述
根据 逆波兰表示法,求表达式的值。
有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
注意 两个整数之间的除法只保留整数部分。
可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
- 解题思路
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
# 每次遇到运算符都要出栈2个数字
stack = []
operator = ["+", "-", "*", "/"]
for item in tokens:
# 数字
if item not in operator:
number = int(item)
stack.append(number)
# 运算符
else:
# 弹出2个操作数
op2 = stack.pop()
op1 = stack.pop()
if item == "+":
stack.append(op1+op2)
elif item == "-":
stack.append(op1-op2)
elif item == "*":
stack.append(op1*op2)
else:
stack.append(int(op1/op2))
print(stack)
print(6//-132)
print(int(6/-132))
return stack[-1]
单调队列
239 滑动窗口最大值
- hard
- 题目描述
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
- 解题思路
# 单调队列,从大到小
class MyQueue:
def __init__(self):
self.queue = []
def push(self, value):
# 把小于当前value的值全部删掉(这里用while是因为可能当前value比窗口中所有值都要大)
while self.queue and value > self.queue[-1]:
self.queue.pop()
self.queue.append(value)
def front(self):
return self.queue[0]
def pop(self, value):
if self.queue and value == self.queue[0]:
self.queue.pop(0)
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
queue = MyQueue()
res = []
# 把前k个元素压入栈中
for i in range(k):
queue.push(nums[i])
res.append(queue.front())
# 计算剩余滑动窗口的最大值
for i in range(k, len(nums)):
# 构成新的窗口
queue.pop(nums[i-k])
queue.push(nums[i])
res.append(queue.front())
return res
优先级队列(堆)
347 前k个高频元素
- medium
- 题目描述
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
- 解题思路
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
# 堆排序,对带权值的元素按照权值进行排序
fre_dict = collections.defaultdict(int)
# 元素和频率的对应关系
for i in nums:
fre_dict[i] += 1
# 优先级队列
pri_que = []
# 小顶堆
for key, value in fre_dict.items():
# 按照频率的大小加入堆中
heapq.heappush(pri_que, (value, key))
# 每次弹出最小值
if len(pri_que) > k:
heapq.heappop(pri_que)
res = [0 for i in range(k)]
# 找出前k个高频元素
for i in range(k-1, -1, -1):
res[i] = heapq.heappop(pri_que)[1]
return res