SWE · Coding

TikTok 两个字符串数组:Trie 求每个查询的最长公共前缀

把第一组全部前缀合进Trie,逐项返回第二组的最长匹配长度,区分公共前缀与完整单词匹配。

题目重点:把第一组全部前缀合进Trie,逐项返回第二组的最长匹配长度,区分公共前缀与完整单词匹配。

题意与假设

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

  • 训练输入为两个字符串数组,返回每个query与任一source字符串的最大公共前缀长度。
  • 比较从字符串开头开始,区分大小写,按code point计长;如果元素是数字需先确认转字符串和负号规则。
  • 空source对应所有答案零;空query答案零。若正式结果是全局最大值,可再对逐query结果取max。

解题路线

  1. 暴力逐query和每个source逐字符比较,复杂度随两数组乘积增长。Trie把source相同前缀存一次,让一次query只沿自己的字符向前走。
  2. 插入source时每读一字符走到对应子节点,没有则创建。这里只问公共前缀长度,不要求匹配结果恰好是source完整单词,因此无需终止标记也能求答案。
  3. query从root开始,首个不存在的字符边前停止。已经走过的深度等于最大公共前缀,因为那条路径至少由一个source插入;不存在下一条边说明没有source能匹配更长。
  4. source=[abcd,abx],query=abcZ走到abc即停,答案3,即使abc不是完整source词也合法。若改成最长完整单词前缀,必须记录最近终止节点,两个问题不可混用。
  5. 返回索引或全部并列source时,需要在节点加代表ID或终止子树信息;不能在当前只存字符边的结构中凭空恢复所有匹配来源。source重复不影响最大长度,但影响列出来源的多重性。
  6. 大型索引可考虑压缩Trie或排序后查询相邻候选,权衡指针开销与构建成本。固定source多次查询可以复用索引;样例函数为演示一次构建加批量查询,不为每项query重建。

手动走一遍

source=[flower,flow,flight],queries=[flute,flowing,z,空串],结果[2,4,0,0]。flowing与flow匹配4字符;flower下一字符e与i不同,不能继续。source=[a]、query=abc结果1,不要求query整体被包含。

Python 参考实现

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

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

"""For every query string, return its longest common prefix with any source string."""

def longest_prefix_lengths(source, queries):
    root = {}
    for word in source:
        node = root
        for char in word:
            node = node.setdefault(char, {})
    result = []
    for word in queries:
        node = root
        matched = 0
        for char in word:
            if char not in node:
                break
            node = node[char]
            matched += 1
        result.append(matched)
    return result

复杂度

设source总字符数S、query总字符数Q,哈希子节点期望 O(S+Q) 时间,Trie空间 O(S),答案 O(query个数)。Unicode归一化或大小写折叠属于额外预处理合同。

易错点与追问

容易失分的边界

  • 把公共前缀误写成完整单词匹配。
  • 把每项答案擅自改成全局最大值。
  • source为空导致max空集合错误。
  • 数字输入默认忽略负号。

继续深挖

  • 如何返回匹配的source ID?
  • 若要最长完整单词前缀怎么改?
  • source频繁删除怎样维护节点引用计数?
  • 排序加二分与Trie在内存上的取舍?
✓已复制微信号!