编程大师-技术-算法-leetcode-2296. 设计一个文本编辑器

5 阅读3分钟

你需要实现一个 ValidWordAbbr 类,核心是预处理字典生成“缩写-单词集合”的映射,从而高效判断目标单词的缩写是否唯一。相比每次遍历字典的暴力解法,预处理能将 isUnique 方法的时间复杂度优化到接近 O(1)(仅生成缩写的时间与单词长度相关),更符合工程最佳实践。

解题思路

  1. 预处理字典
    • 构造函数接收字典后,遍历所有单词,为每个单词生成缩写;
    • HashMap<String, Set<String>> 存储映射关系:key 是缩写,value 是该缩写对应的所有不同单词的集合(用 Set 去重,避免字典中重复单词干扰判断)。
  2. 唯一性判断逻辑
    • 生成目标单词的缩写;
    • 若字典中无该缩写 → 唯一(返回 true);
    • 若字典中有该缩写,检查对应的单词集合:
      • 若集合中只有当前单词本身 → 唯一(返回 true);
      • 否则 → 不唯一(返回 false)。

完整Java代码

import java.util.Deque;
import java.util.LinkedList;

public class TextEditor {
    // 光标左侧字符:用StringBuilder,支持O(1)截取最后10个字符、O(1)删除末尾字符
    private final StringBuilder left;
    // 光标右侧字符:Deque(队首是光标后第一个字符)
    private final Deque<Character> right;

    public TextEditor() {
        left = new StringBuilder();
        right = new LinkedList<>();
    }

    // 添加文本:O(n)(n为text长度),仅追加到left末尾,高效
    public void addText(String text) {
        left.append(text);
    }

    // 删除左侧k个字符:O(k),最多删除left.length()个
    public int deleteText(int k) {
        int deleteCount = Math.min(k, left.length());
        left.delete(left.length() - deleteCount, left.length());
        return deleteCount;
    }

    // 光标左移k次:O(k),返回左侧最多10个字符
    public String cursorLeft(int k) {
        int move = Math.min(k, left.length());
        // 从left末尾取出move个字符,加入right队首(保持顺序)
        for (int i = 0; i < move; i++) {
            char c = left.charAt(left.length() - 1);
            left.deleteCharAt(left.length() - 1);
            right.offerFirst(c);
        }
        // 截取最后10个字符:O(1)(常数时间)
        return getLeftTop10();
    }

    // 光标右移k次:O(k),返回左侧最多10个字符
    public String cursorRight(int k) {
        int move = Math.min(k, right.size());
        // 从right队首取出move个字符,加入left末尾
        for (int i = 0; i < move; i++) {
            char c = right.pollFirst();
            left.append(c);
        }
        // 截取最后10个字符:O(1)(常数时间)
        return getLeftTop10();
    }

    // 核心优化:O(1) 截取左侧最后10个字符(无遍历)
    private String getLeftTop10() {
        int len = left.length();
        int start = Math.max(0, len - 10);
        // substring是O(1)(底层是字符数组引用,非拷贝)
        return left.substring(start, len);
    }

    // 测试用例(和题目示例一致)
    public static void main(String[] args) {
        TextEditor textEditor = new TextEditor();
        textEditor.addText("leetcode");
        System.out.println(textEditor.deleteText(4)); // 4
        textEditor.addText("practice");
        System.out.println(textEditor.cursorRight(3)); // "etpractice"
        System.out.println(textEditor.cursorLeft(8)); // "leet"
        System.out.println(textEditor.deleteText(10)); // 4
        System.out.println(textEditor.cursorLeft(2)); // ""
        System.out.println(textEditor.cursorRight(6)); // "practi"
    }
}

代码关键部分解释

  1. 映射结构 abbrToWords
    • HashMap 存储缩写与单词集合的映射,预处理一次字典即可复用,避免每次 isUnique 遍历字典;
    • Set 存储单词,自动去重(比如字典中有多个 "a",仅存一个,不影响判断)。
  2. 缩写生成方法 getAbbreviation
    • 严格遵循题目规则:长度 ≤ 2 直接返回单词,长度 > 2 拼接首字母、中间长度、尾字母。
  3. isUnique 核心逻辑
    • 先判断缩写是否存在,不存在则直接唯一;
    • 若存在,仅当“缩写对应的单词集合只有当前单词”时,才满足唯一条件(符合题目中“所有缩写相同的单词都与word相同”的规则)。

复杂度分析

  • 初始化(构造函数):O(n * L),n 是字典单词数,L 是单词平均长度(生成缩写的时间);
  • isUnique 方法:O(L),仅需生成目标单词的缩写(L 是目标单词长度),后续哈希表和集合操作都是 O(1)。

总结

  1. 核心优化点:预处理字典生成缩写-单词集合映射,避免重复遍历字典,提升多次调用 isUnique 的效率;
  2. 唯一性判断的关键:要么缩写不存在,要么缩写对应的所有单词都是当前单词;
  3. 边界处理:兼容空字典、重复单词、短单词(长度≤2)等场景,保证逻辑正确性。