UNIT 01局部归约
#20 有效的括号
- 待处理状态
- 尚未匹配的左括号栈。
- 触发与归约
- 右括号只与最近一个未匹配左括号配对。
- 结构不变量
- 栈底到栈顶按出现顺序保存全部未闭合左括号。
- 输出与边界
- 空栈遇右括号即失败,最终栈必须为空。
迁移 · #921 使括号有效的最少添加最少添加括号把失败改为补充缺失括号并统计数量。
先说清契约,再独立实现进入本单元 ↗
Unit 00 · 栈、队列与待处理状态
栈让最近进入、尚未解决的对象先离开;队列让等待最久的对象先离开。本单元不背 API,而是通过操作动画建立“进入顺序—离开顺序—待处理状态”的统一模型。
top/front 不修改状态,pop/dequeue 会修改状态;后进先出。栈顶是最近进入且尚未离开的对象,典型场景包括撤销、嵌套与最近未匹配状态。
先进先出。队首是等待时间最长的对象,队尾接收新任务,典型场景包括排队、缓冲与任务调度。
容器通常只保存尚未解决、尚未消费或未来仍有用的对象,而不是无差别保存全部输入历史。
空栈或空队列不存在可移除对象。执行 pop/dequeue 前必须明确空状态如何处理。
栈与队列:理解待处理状态,掌握栈、队列与单调结构。
这里的梯度描述认知任务的递进,不等同于题库的难度标签。点击题目可进入对应单元。
用同一组问题定位每个单元,再观察迁移题改变了哪个条件。进入写代码环节后,学习地图会收起,留出独立思考的空间。
from collections import deque
class Stack:
def __init__(self):
self._data = []
def push(self, value):
self._data.append(value)
def top(self):
if not self._data:
raise IndexError("top from empty stack")
return self._data[-1]
def pop(self):
if not self._data:
raise IndexError("pop from empty stack")
return self._data.pop()
def empty(self):
return not self._data
class Queue:
def __init__(self):
self._data = deque()
def enqueue(self, value):
self._data.append(value)
def front(self):
if not self._data:
raise IndexError("front from empty queue")
return self._data[0]
def dequeue(self):
if not self._data:
raise IndexError("dequeue from empty queue")
return self._data.popleft()
def empty(self):
return not self._data
下面四个场景不只是关键词匹配。请先确定容器保存的对象,再判断出口应该指向“最近进入者”还是“等待最久者”。
扫描字符串时,栈只保存尚未匹配的左括号。右括号到达时必须消费最近一个左括号;空栈遇到右括号立即失败。
def valid_single_parentheses(s: str) -> bool:
stack = []
for char in s:
if char == "(":
stack.append(char)
else:
if not stack:
return False
stack.pop()
return not stack
先不要问“这题是不是栈题”。先问:当前有哪些对象尚未解决?下一个应该被处理的是最近进入者,还是等待最久者?这一访问规则决定使用栈或队列。