SWE · Coding

Amazon Trie前缀查询:完整词与子树结果

维护词典并按前缀返回候选,区分词结束标记、空前缀和输出排序成本。

题目重点:维护词典并按前缀返回候选,区分词结束标记、空前缀和输出排序成本。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 补充问点明确需要按prefix查询,基础题号与返回格式没有完整给定。练习定义add、contains和prefix_words,后者返回全部不同词且字典序;不担保实际题只要此API。
  • 精确区分大小写和Unicode码点,词典允许空词,空前缀返回全部词。重复插入同词不创建重复候选;删除/TopK权重不是基础操作。

解题路线

  1. 每字符沿child map下降,词尾用None键标记,避免用#与合法字符冲突。contains必须既找到节点又有terminal,前缀存在不代表完整词。
  2. prefix_words先沿前缀找到子树,再迭代DFS收集terminal对应文字。不存在前缀返回[];词本身也是前缀匹配,应在子树根检查terminal。
  3. 示例存stack的完整path字符串,便于读取,但每次text+ch有复制成本;结果统一sorted实现练习的字典序,不把dict遍历顺序当排序。
  4. 若只要是否存在前缀,无需展开子树;若需要最多K候选,可按字典序遍历/缓存,但频繁更新要维护缓存一致性。频率TopK还需权重与并列合同,不能靠当前字典序实现。

手动走一遍

词典[car,cat,ca],contains(ca)true、contains(c)false;prefix_words(ca)=[ca,car,cat]。词典含#字符时仍合法,因为terminal不是字符串#。

Python 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

class PrefixDictionary:
    def __init__(self,words=()):
        self.root={}
        for word in words:self.add(word)
    def add(self,word):
        node=self.root
        for ch in word:node=node.setdefault(ch,{})
        node[None]=True
    def _node(self,text):
        node=self.root
        for ch in text:
            if ch not in node:return None
            node=node[ch]
        return node
    def contains(self,word):
        node=self._node(word)
        return node is not None and None in node
    def prefix_words(self,prefix):
        node=self._node(prefix)
        if node is None:return []
        result=[];stack=[(node,prefix)]
        while stack:
            current,text=stack.pop()
            if None in current:result.append(text)
            for ch,child in current.items():
                if ch is not None:stack.append((child,text+ch))
        return sorted(result)

复杂度

构建读取总字符D,节点O(D),contains长度L平均O(L)map访问。prefix枚举需访问子树V节点,当前路径复制成本按各访问节点路径长度之和计;R结果排序还需O(R log R)比较且比较成本随字符长度增加。stack及路径复制也需空间,不能说所有prefix请求O(L)。

易错点与追问

容易失分的边界

  • 仅存在child路径就返回完整词true。
  • 用合法字符作为terminal导致碰撞。
  • 漏掉结果输出/排序/字符串复制成本。

继续深挖

  • 若要删除词,如何删除terminal但保留其他词共享节点?
  • 空前缀结果巨大时怎样分页且保持版本稳定?
✓已复制微信号!