LeetCode 题解工作台

最长公共后缀查询

给你两个字符串数组 wordsContainer 和 wordsQuery 。 对于每个 wordsQuery[i] ,你需要从 wordsContainer 中找到一个与 wordsQuery[i] 有 最长公共后缀 的字符串。如果 wordsContainer 中有两个或者更多字符串有最长公共后…

category

3

题型

code_blocks

5

代码语言

hub

3

相关题

当前训练重点

困难 · 数组·string

bolt

答案摘要

题目需要我们找到最长公共后缀,我们可以考虑使用字典树。 我们定义字典树的节点结构如下:

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 数组·string 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你两个字符串数组 wordsContainer 和 wordsQuery 。

对于每个 wordsQuery[i] ,你需要从 wordsContainer 中找到一个与 wordsQuery[i] 有 最长公共后缀 的字符串。如果 wordsContainer 中有两个或者更多字符串有最长公共后缀,那么答案为长度 最短 的。如果有超过两个字符串有 相同 最短长度,那么答案为它们在 wordsContainer 中出现 更早 的一个。

请你返回一个整数数组 ans ,其中 ans[i] wordsContainer中与 wordsQuery[i] 有 最长公共后缀 字符串的下标。

 

示例 1:

输入:wordsContainer = ["abcd","bcd","xbcd"], wordsQuery = ["cd","bcd","xyz"]

输出:[1,1,1]

解释:

我们分别来看每一个 wordsQuery[i] :

  • 对于 wordsQuery[0] = "cd" ,wordsContainer 中有最长公共后缀 "cd" 的字符串下标分别为 0 ,1 和 2 。这些字符串中,答案是下标为 1 的字符串,因为它的长度为 3 ,是最短的字符串。
  • 对于 wordsQuery[1] = "bcd" ,wordsContainer 中有最长公共后缀 "bcd" 的字符串下标分别为 0 ,1 和 2 。这些字符串中,答案是下标为 1 的字符串,因为它的长度为 3 ,是最短的字符串。
  • 对于 wordsQuery[2] = "xyz" ,wordsContainer 中没有字符串跟它有公共后缀,所以最长公共后缀为 "" ,下标为 0 ,1 和 2 的字符串都得到这一公共后缀。这些字符串中, 答案是下标为 1 的字符串,因为它的长度为 3 ,是最短的字符串。

示例 2:

输入:wordsContainer = ["abcdefgh","poiuygh","ghghgh"], wordsQuery = ["gh","acbfgh","acbfegh"]

输出:[2,0,2]

解释:

我们分别来看每一个 wordsQuery[i] :

  • 对于 wordsQuery[0] = "gh" ,wordsContainer 中有最长公共后缀 "gh" 的字符串下标分别为 0 ,1 和 2 。这些字符串中,答案是下标为 2 的字符串,因为它的长度为 6 ,是最短的字符串。
  • 对于 wordsQuery[1] = "acbfgh" ,只有下标为 0 的字符串有最长公共后缀 "fgh" 。所以尽管下标为 2 的字符串是最短的字符串,但答案是 0 。
  • 对于 wordsQuery[2] = "acbfegh" ,wordsContainer 中有最长公共后缀 "gh" 的字符串下标分别为 0 ,1 和 2 。这些字符串中,答案是下标为 2 的字符串,因为它的长度为 6 ,是最短的字符串。

 

提示:

  • 1 <= wordsContainer.length, wordsQuery.length <= 104
  • 1 <= wordsContainer[i].length <= 5 * 103
  • 1 <= wordsQuery[i].length <= 5 * 103
  • wordsContainer[i] 只包含小写英文字母。
  • wordsQuery[i] 只包含小写英文字母。
  • wordsContainer[i].length 的和至多为 5 * 105 。
  • wordsQuery[i].length 的和至多为 5 * 105 。
lightbulb

解题思路

方法一:字典树

题目需要我们找到最长公共后缀,我们可以考虑使用字典树。

我们定义字典树的节点结构如下:

  • children:一个长度为 26 的数组,用于存储子节点。
  • length:当前节点的最短字符串长度。
  • idx:当前节点的字符串下标。

我们遍历字符串数组 wordsContainer,将每个字符串倒序插入字典树中。在插入的过程中,我们更新每个节点的 lengthidx

接下来,我们遍历字符串数组 wordsQuery,对于每个字符串,我们从字典树中查找最长公共后缀的字符串下标,在寻找的过程中,如果遇到空节点,说明往后没有公共后缀了,我们可以直接返回当前节点的 idx

时间复杂度 (L1×Σ+L2)(L_1 \times |\Sigma| + L_2),空间复杂度 O(L1×Σ)O(L_1 \times |\Sigma|),其中 L1L_1L2L_2 分别是 wordsContainerwordsQuery 的字符串长度之和;而 Σ\Sigma 是字符集大小,本题中 Σ=26\Sigma = 26

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Trie:
    __slots__ = ("children", "length", "idx")

    def __init__(self):
        self.children = [None] * 26
        self.length = inf
        self.idx = inf

    def insert(self, w: str, i: int):
        node = self
        if node.length > len(w):
            node.length = len(w)
            node.idx = i
        for c in w[::-1]:
            idx = ord(c) - ord("a")
            if node.children[idx] is None:
                node.children[idx] = Trie()
            node = node.children[idx]
            if node.length > len(w):
                node.length = len(w)
                node.idx = i

    def query(self, w: str) -> int:
        node = self
        for c in w[::-1]:
            idx = ord(c) - ord("a")
            if node.children[idx] is None:
                break
            node = node.children[idx]
        return node.idx


class Solution:
    def stringIndices(
        self, wordsContainer: List[str], wordsQuery: List[str]
    ) -> List[int]:
        trie = Trie()
        for i, w in enumerate(wordsContainer):
            trie.insert(w, i)
        return [trie.query(w) for w in wordsQuery]
speed

复杂度分析

指标
时间complexity depends on total characters in wordsContainer and wordsQuery for building and traversing the trie, roughly O(sum of lengths). Space complexity is also O(sum of lengths) for the trie structure.
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    You are reversing strings to simplify the suffix problem.

  • question_mark

    You need to track multiple tie-breaking rules: length and index.

  • question_mark

    Efficient matching requires a trie or hashmap, naive comparisons will timeout.

warning

常见陷阱

外企场景
  • error

    Ignoring tie-breaker rules can yield incorrect indices.

  • error

    Using naive suffix comparison for every query causes timeouts.

  • error

    Forgetting to reverse strings before building the trie changes logic.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Find longest common suffix with at most k mismatches.

  • arrow_right_alt

    Return the actual matching string instead of index.

  • arrow_right_alt

    Handle dynamic insertion and deletion in wordsContainer.

help

常见问题

外企场景

最长公共后缀查询题解:数组·string | LeetCode #3093 困难