**操作历史管理器的撤销/重做能力**
2026 华为OD机试真题 4月29日华为OD上机新系统考试真题 100 分题型
点击查看华为 OD 机试真题完整目录:2026最新华为OD机试新系统卷 + 双机位C卷 真题题库目录|全覆盖题库 + 逐点算法考点详解
题目描述
实现一个操作历史管理器,使用双向链表存储执行过的操作。支持执行新操作、撤销和重做功能。
输入描述
- 执行操作($execute$ {操作描述}):执行新操作,并清除当前操作之后的所有历史记录
- 撤销($undo$):回退到上一个操作状态(上一个操作状态可以为从未执行过任何操作的状态,若当前状态已经是从未执行过任何操作的状态,则 $undo$ 失败)
- 重做($redo$):前进到下一个操作状态(下一个操作状态是之前撤销过的操作,若没有进行过撤销操作(即链表的下一个操作状态不存在),则 $redo$ 失败)
说明
命令只会出现 $execute$ {操作描述}、$undo$、$redo$ 三种类型
输出描述
-
执行完所有命令后,返回当前操作的描述
-
若执行 $undo$ 时,当前状态是从未执行过任何操作的状态,立即返回 "$undo$ $failed$",不继续执行后续命令。(注意:$undo$ 可以撤销到从未执行过任何操作的状态)
-
若执行 $redo$ 时无下一个操作,立即返回 "$redo$ $failed$",不继续执行后续命令
-
若当前状态是从未执行过任何操作,当前操作描述为空字符串 ""
示例1
输入
[["execute", "insert hello"], ["execute", "newline"], ["execute", "insert woo"], ["undo"], ["execute", "insert world"], ["undo"]]
输出
"newline"
说明
执行 $insert$ $hello$ $→$ 当前:$insert$ $hello$
执行 $newline$ $→$ 当前:$newline$
执行 $insert$ $woo$ $→$ 当前:$insert$ $woo$
撤销 $→$ 当前:$newline$(当前回滚到上一步的状态)
执行 $insert$ $world$ $→$ 当前:$insert$ $world$(清除任何后续历史)
撤销 $→$ 当前:$newline$
示例2
输入
[[]]
输出
""
说明
当前状态是从未执行过任何操作,输出: ""
示例3
输入
[["execute", "insert hello"], ["undo"]]
输出
""
说明
执行 $insert$ $hello$ $→$ 当前:$insert$ $hello$
撤销 $→$ 当前:""(当前状态是从未执行过任何操作,输出: "")
示例4
输入
[["execute","insert hello"],["undo"],["redo"]]
输出
"insert hello"
说明
执行 $insert$ $hello$ $→$ 当前:$insert$ $hello$
撤销 $→$ 当前:""
重做 $→$ 当前:$insert$ $hello$
解题思路
核心思想
本题要求实现一个操作历史管理器,核心在于维护一个操作序列和一个指向当前操作的指针(游标)。
- 存储结构:可以使用动态数组(如 Java 的
ArrayList、Python 的list)或双向链表来存储执行过的操作描述。 - 指针维护:使用一个整数变量
cur表示当前所处的操作索引。初始状态下,没有任何操作,cur = -1。 - 操作处理:
- execute {op}:
- 首先需要清空当前指针
cur之后的所有历史记录(因为新操作会覆盖掉撤销后的重做路径)。 - 将新操作添加到序列末尾。
- 将指针
cur指向序列的最后一个元素。
- 首先需要清空当前指针
- undo:
- 如果
cur == -1,说明已经回退到初始状态,无法再撤销,返回 "undo failed"。 - 否则,将
cur减 1。
- 如果
- redo:
- 如果
cur已经指向序列的最后一个元素,说明没有可以重做的操作,返回 "redo failed"。 - 否则,将
cur加 1。
- 如果
- execute {op}:
- 结果返回:
- 遍历完所有指令后,根据
cur的值返回对应的操作描述。如果cur == -1,返回空字符串""。
- 遍历完所有指令后,根据
复杂度分析
- 时间复杂度:$O(N \times M)$,其中 $N$ 是命令的数量,$M$ 是每次
execute时清空后续历史的开销。在最坏情况下,如果频繁在中间位置执行execute,清空操作可能达到 $O(N)$。不过在实际应用中,如果使用链表或者仅移动尾部索引,可以优化到 $O(1)$。 - 空间复杂度:$O(N \times L)$,其中 $N$ 是执行的操作数量,$L$ 是操作描述字符串的平均长度。我们需要存储所有的历史操作。