栈、单调栈与单调队列 · HTML
数学 / 逻辑形态
从左到右读取 token。每个 token 触发 push、pop、reduce 或修改栈顶;栈内容是处理当前前缀后仍会影响未来的最小上下文集合。
识别信号
- 结构具有嵌套、最近开启先关闭的 LIFO 关系。
- 操作语义包含 undo、back、return 或 collapse。
- 递归调用可用显式 frame 模拟。
- 读取新 token 时只需查看最近未完成上下文。
容易误判的相似信号
| Signal | Why it is different |
|---|
| 先进先出的事件处理 | 若最早到达者必须先处理,应使用 queue。 |
| 只需括号合法性 | 可用更窄、更易证明的 balanced-delimiter-stack 模板。 |
核心不变量
处理完输入前缀后,栈自底向上按开启顺序保存所有尚未完成的上下文;栈顶是下一 token 唯一可直接影响的最近上下文。
状态、转移与处理顺序
| Item | Definition |
|---|
| State | token 游标、frame 栈;每个 frame 仅保存恢复父上下文所必需的信息。 |
| Transition | 开启事件 push frame,关闭事件 pop 并归约到父 frame,普通 token 更新栈顶状态。 |
| Frontier / order | 从最早未完成到最近未完成的上下文链,只有栈顶暴露给下一步。 |
Python 骨架
def normalize_path(parts):
stack = []
for part in parts:
if part in ('', '.'):
continue
if part == '..':
if stack:
stack.pop()
else:
stack.append(part)
return '/' + '/'.join(stack)
正确性思路
- 普通片段被追加为当前最深上下文,保持原顺序。
- 父级操作只撤销最近一个仍有效片段,LIFO 正好匹配语义。
- 归纳处理所有 token 后,栈恰含未被撤销的规范路径片段。
复杂度
| Time | Space | Parameters |
|---|
| O(n) | O(d) | n 为 token 总长度/数量,d 为最大未闭合深度;字符串拼接成本需计入输出长度。 |
边界条件
- 空输入产生基础状态。
- 在根级继续 pop 必须按语义忽略或报错。
- 连续多个开启/关闭会达到最大深度。
- 结束时栈非空可能是合法未归约结果,也可能表示输入不完整,取决于协议。
错误模式
| Pattern | Why it fails / fix |
|---|
| frame 保存过多 | 把完整前缀复制进每层会从 O(n) 膨胀到 O(n²)。 |
| pop 空栈 | 关闭/撤销前必须定义无上下文时的语义。 |
| 把当前值与父值混淆 | 先写清 frame 字段以及 pop 后如何归约。 |
选择与排除规则
- 最近开启必须最先结束:栈。
- 只是匹配定界符:用专用 balanced 模板。
- 需要优先弹出最大/最小候选:不是普通状态栈,考虑堆或单调结构。
相关模板
原创微型例子
| 环节 | 内容 |
|---|
| Result | 规范结果 /home/pics/2026。 |
| Setup | 路径片段 [home,docs,..,pics,.,2026]。 |
| Trace | home/docs 入栈,.. 弹 docs,忽略 .,再压 pics/2026。 |
Recall prompts
我的补充