栈、单调栈与单调队列 · HTML
数学 / 逻辑形态
扫描 token;开放符入栈。关闭符要求栈非空且 top=matching_open(close),然后弹出。结束时栈空当且仅当全部定界符平衡。
识别信号
- 输入包含括号、标签、begin/end 等成对符号。
- 嵌套必须正确,交叉配对不允许。
- 要找未匹配位置或最大嵌套深度。
- 最近开放符决定当前关闭符是否合法。
容易误判的相似信号
| Signal | Why it is different |
|---|
| 只有一种括号且只问数量 | 有时 balance 计数器已足够,但多类型必须用栈防止交叉。 |
| 任意删除后可合法 | 若要求最少删除或所有修复方案,单次验证栈只是子步骤。 |
核心不变量
扫描前缀后,栈按出现顺序保存且仅保存尚未匹配的开放符;栈顶是唯一允许被下一个关闭符匹配的开放符。
状态、转移与处理顺序
| Item | Definition |
|---|
| State | 开放符/索引栈、close→open 映射、可选最大深度或错误位置。 |
| Transition | 开放符 push;关闭符先检查非空与类型,匹配则 pop,否则立即失败或记录修复。 |
| Frontier / order | 所有未闭合嵌套层;越靠栈顶越晚开启、越早需要关闭。 |
Python 骨架
def delimiters_balanced(text):
match = {')': '(', ']': '[', '}': '{'}
opening = set(match.values())
stack = []
for ch in text:
if ch in opening:
stack.append(ch)
elif ch in match:
if not stack or stack[-1] != match[ch]:
return False
stack.pop()
return not stack
正确性思路
- 每个开放符入栈且只在与正确关闭符配对时弹出,所以生成的配对类型正确。
- LIFO 强制内层先闭合,排除交叉配对。
- 遇到不匹配即无任何其他更早开放符可合法跨过栈顶;结束空栈恰表示无剩余开放符。
复杂度
| Time | Space | Parameters |
|---|
| O(n) | O(d) | n 为输入长度,d 为最大嵌套深度,最坏 d=n。 |
边界条件
- 空串通常合法。
- 首字符为关闭符应立即失败。
- 结束时剩余开放符意味着不完整。
- 普通非定界字符是忽略、拒绝还是 token 内容须按协议决定。
错误模式
| Pattern | Why it fails / fix |
|---|
| 只统计开闭数量 | ([)] 数量平衡但嵌套错误。 |
| 访问 stack[-1] 前不判空 | 多余关闭符会触发异常。 |
| 最终不检查栈空 | 会把缺少关闭符的前缀误判为合法。 |
选择与排除规则
- 多类型或需位置:栈。
- 单类型且只验证、无需位置:计数器可能足够。
- 最长合法段通常在栈中保存索引而不是字符。
相关模板
| Relation | Template | Boundary |
|---|
| 修复/配对扩展 | 区间 DP | 允许删除或插入并求最优合法化成本。 |
| 专用化 | 栈式状态模拟 | 复杂 frame 被缩成一个开放符或索引。 |
原创微型例子
| 环节 | 内容 |
|---|
| Result | 栈为空,嵌套合法。 |
| Setup | 符号流 { [ ] ( ) }。 |
| Trace | 依次压 {、[,] 弹 [;压 (,) 弹 (;} 弹 {。 |
Recall prompts
我的补充