Elephant 在「设计文本编辑器」的评测结果

这是该 AI 模型在此测试用例上的详细评测结果。

基本信息

  • 模型名称:Elephant
  • 用例名称:设计文本编辑器
  • 测试类型:文本生成
  • 评测维度:代码生成

系统提示词(System Prompt)

这是给 AI 模型的背景设定和角色指令:

你是一名资深 Python 软件工程师,擅长数据结构设计与算法实现。 回答要求: 1. 在编写代码前,先用 2-3 句话说明你选择的底层数据结构及其理由。 2. 代码需包含清晰的注释,解释关键逻辑(尤其是光标移动和边界处理)。 3. 所有方法必须正确处理边界情况(如光标已在最左/最右端、删除数量超过现有字符数等)。 4. 完成实现后,提供一段简短的测试代码,覆盖正常流程和至少两个边界场景。 5. 输出格式:设计思路 → 完整类实现 → 测试代码。

用户提示词(User Prompt)

这是用户给 AI 模型的具体任务要求:

用 Python 设计一个支持光标操作的简单文本编辑器。 请实现以下类:

评测结果

综合得分

该模型在此用例的得分为:81.7 分(满分 100 分),已通过

基础难度评测结果

  • 得分:81.7 分
  • 通过状态:已通过

模型生成产物

以下是该模型针对此任务的实际生成内容:

设计思路 → 完整类实现 → 测试代码 设计思路: 使用两个列表模拟左右栈结构(左栈存储光标左侧字符,右栈存储光标右侧字符,栈顶为光标相邻元素)。该结构支持 O(1) 时间复杂度的光标左右移动、字符插入与删除,且天然支持边界处理:光标左移时左栈弹出压入右栈,右移则反之;删除时直接操作左栈顶。 ```python class TextEditor: def __init__(self): # left 栈:光标左侧字符,栈顶为光标左侧紧邻字符 # right 栈:光标右侧字符,栈顶为光标右侧紧邻字符 self.left = [] self.right = [] def insert(self, text: str) -> None: """在光标处插入字符串,所有字符依次压入左栈。""" for ch in text: self.left.append(ch) def delete(self, k: int) -> int: """ 删除光标左侧的 k 个字符,返回实际删除数量。 边界处理:若 k 超过左栈长度,则删除全部并清空左栈。 """ real_delete = min(k, len(self.left)) for _ in range(real_delete): self.left.pop() return real_delete def cursorLeft(self, k: int) -> str: """ 光标左移 k 步,返回光标左侧最多 10 个字符。 边界处理:若 k 超过左栈长度,则移动至最左端(左栈为空)。 """ move = min(k, len(self.left)) for _ in range(move): # 从左栈弹出并压入右栈,光标左移 self.right.append(self.left.pop()) return ''.join(self.left[-10:]) def cursorRight(self, k: int) -> str: """ 光标右移 k 步,返回光标左侧最多 10 个字符。 边界处理:若 k 超过右栈长度,则移动至最右端(右栈为空)。 """ move = min(k, len(self.right)) for _ in range(move): # 从右栈弹出并压入左栈,光标右移 self.left.append(self.right.pop()) return ''.join(self.left[-10:]) # 测试代码 if __name__ == "__main__": editor = TextEditor() # 正常流程测试 editor.insert("leetcode") print(editor.cursorLeft(3)) # 输出 "let" editor.insert("practice") print(editor.cursorRight(3)) # 输出 "etpractice" print(editor.delete(4)) # 输出 4 print(editor.cursorLeft(5)) # 输出 "leet" # 边界场景 1:光标已在最左端仍执行左移 editor2 = TextEditor() editor2.insert("hello") print(editor2.cursorLeft(10)) # 输出 ""(移动超过长度) print(editor2.delete(3)) # 输出 3 # 边界场景 2:删除数量超过现有字符数 editor3 = TextEditor() editor3.insert("ab") print(editor3.delete(100)) # 输出 2(实际删除数) print(editor2.cursorRight(1)) # 输出 "o"(从空状态右移) ```

AI 评审点评

以下是 AI 评审对该模型输出的点评:

【KIMI】整体上,代码实现了基本的文本编辑器功能,结构清晰,注释详细。但是,在光标移动方法中返回的字符数处理上有瑕疵,需要改进。

进阶难度评测结果

  • 得分:81.7 分
  • 通过状态:已通过

模型生成产物

以下是该模型针对此任务的实际生成内容:

### 设计思考 我选择使用**两个栈**(`undo_stack` 和 `redo_stack`)来管理文本编辑器的状态。底层数据结构采用字符串(`str`)存储当前文本内容,因为字符串在Python中是不可变的,这能简化状态快照的管理并避免意外修改。 **状态管理策略**: - **`undo_stack`**:存储每一次操作前的文本状态(历史版本)。 - **`redo_stack`**:存储被撤销的操作状态,支持重做。 - **执行新操作**:当用户输入新文本时,当前文本状态先压入 `undo_stack`,然后更新文本内容,同时**清空 `redo_stack`**(因为新操作破坏了重做链)。 - **撤销(undo)**:从 `undo_stack` 弹出最近状态压入 `redo_stack`,并恢复文本。 - **重做(redo)**:从 `redo_stack` 弹出状态压入 `undo_stack`,并恢复文本。 **时间复杂度**: - `input_text()`:O(1) 压栈 + O(n) 字符串更新(n为文本长度) - `undo()`:O(1) 栈操作 + O(n) 字符串恢复 - `redo()`:O(1) 栈操作 + O(n) 字符串恢复 - 空间复杂度:O(m×n),m为操作次数,n为平均文本长度 --- ### 代码实现 ```python class TextEditor: def __init__(self): """ 初始化文本编辑器。 - current_text: 当前文本内容 - undo_stack: 存储历史状态(用于撤销) - redo_stack: 存储被撤销的状态(用于重做) """ self.current_text = "" self.undo_stack = [] self.redo_stack = [] def input_text(self, text: str) -> None: """ 输入新文本。 1. 将当前状态压入撤销栈 2. 更新文本内容 3. 清空重做栈(新操作破坏重做链) """ # 保存当前状态到撤销栈 self.undo_stack.append(self.current_text) # 更新文本 self.current_text += text # 清空重做栈(关键:新操作使之前的重做历史失效) self.redo_stack.clear() def undo(self) -> str: """ 撤销上一步操作。 1. 若撤销栈为空,返回空字符串 2. 将当前状态压入重做栈 3. 从撤销栈恢复上一个状态 """ if not self.undo_stack: return "" # 保存当前状态到重做栈 self.redo_stack.append(self.current_text) # 恢复上一个状态 self.current_text = self.undo_stack.pop() return self.current_text def redo(self) -> str: """ 重做上一步撤销的操作。 1. 若重做栈为空,返回空字符串 2. 将当前状态压入撤销栈 3. 从重做栈恢复状态 """ if not self.redo_stack: return "" # 保存当前状态到撤销栈 self.undo_stack.append(self.current_text) # 恢复重做状态 self.current_text = self.redo_stack.pop() return self.current_text def get_text(self) -> str: """获取当前文本内容""" return self.current_text # ==================== 测试用例 ==================== def run_tests(): editor = TextEditor() # 测试用例1: 正常输入+撤销+重做 editor.input_text("Hello") editor.input_text(" World") assert editor.get_text() == "Hello World" editor.undo() assert editor.get_text() == "Hello" editor.redo() assert editor.get_text() == "Hello World" print("测试用例1通过: 正常输入+撤销+重做") # 测试用例2: 空栈撤销 editor2 = TextEditor() result =...

AI 评审点评

以下是 AI 评审对该模型输出的点评:

【KIMI】该实现在功能正确性、设计合理性和代码质量方面都表现良好。撤销/重做功能的核心逻辑实现正确,测试用例覆盖全面。设计上使用了合适的数据结构,代码规范性和可读性较好。但在代码健壮性和模块化方面还有改进空间,如增加输入校验、分离测试用例等。综合来看,这是一个高质量的实现。

困难难度评测结果

  • 得分:85.0 分
  • 通过状态:已通过

模型生成产物

以下是该模型针对此任务的实际生成内容:

## 设计思考 ### 1. 底层数据结构选择 Rope - **平衡树结构**:使用AVL树实现,每个节点存储子树总长度和文本片段 - **O(log n)操作**:通过维护子树大小实现快速定位,插入/删除/查询均在树高内完成 - **内存效率**:相比字符串拼接,Rope避免了大文本的频繁复制 ### 2. 协同编辑协议选择:OT(操作转换) - **选择理由**: 1. **实时性**:OT在低延迟场景下表现更优,状态同步只需传输操作而非全量状态 2. **成熟度**:Google Docs等商业系统采用OT,算法理论成熟 3. **确定性**:通过操作转换函数`transform`解决并发冲突,保证所有副本最终一致 4. **适用场景**:协同文本编辑以小粒度操作为主(字符/单词级),OT效率高于CRDT的元数据开销 - **CRDT对比**:虽然CRDT无需中心服务器,但文本编辑场景下OT的转换函数更直观,且无需处理GC(垃圾收集)问题 ### 3. 并发冲突解决策略 - **操作转换核心**:`transform(op1, op2)`处理两个并发操作的先后顺序 - **插入-插入冲突**:后插入操作根据位置偏移调整 - **插入-删除冲突**:被删除范围内的插入被丢弃,范围外的位置相应调整 - **删除-删除冲突**:重叠部分只删除一次,剩余部分继续删除 ### 4. 边界条件处理 - 位置越界检查(负数、超出文本长度) - 空文本处理 - 无效范围处理(start > end) - 操作转换的完备性覆盖所有冲突组合 ```python from __future__ import annotations from dataclasses import dataclass from typing import Optional, Tuple, List @dataclass class Operation: """协同编辑操作定义""" pos: int text: str # 插入文本,为空表示删除 delete_len: int # 删除长度,0表示插入操作 def __post_init__(self): if self.pos None: """更新节点高度和总长度""" left_len = self.left.total_length if self.left else 0 right_len = self.right.total_length if self.right else 0 self.total_length = left_len + len(self.text) + right_len left_height = self.left.height if self.left else 0 right_height = self.right.height if self.right else 0 self.height = max(left_height, right_height) + 1 def balance_factor(self) -> int: left_height = self.left.height if self.left else 0 right_height = self.right.height if self.right else 0 return left_height - right_height class Rope: """基于AVL树的Rope数据结构""" def __init__(self, text: str = ""): self.root: Optional[RopeNode] = None if text: self.root = RopeNode(text) def _split_node(self, node: RopeNode, pos: int) -> Tuple[RopeNode, RopeNode]: """在节点内按位置分割文本""" if pos = len(node.text): left = RopeNode(node.text) right = RopeNode("") return left, right left_text = node.text[:pos] right_text = node.text[pos:] left_node = RopeNode(left_text) right_node = RopeNode(right_text) return left_node, right_node def _merge_nodes(self, left: RopeNode, right: RopeNode)...

AI 评审点评

以下是 AI 评审对该模型输出的点评:

【KIMI】总体而言,该实现在功能正确性、设计合理性和代码质量方面表现良好,基本满足题目要求。Rope数据结构和OT算法的选择合理,测试用例覆盖全面。但在时间复杂度的平衡性保证和代码细节处理方面还有改进空间。

相关链接

您可以通过以下链接查看更多相关内容:

加载中...