LeetCode 题解工作台

匹配子序列的单词数

给定字符串 s 和字符串数组 words , 返回 words[i] 中是 s 的子序列的单词个数 。 字符串的 子序列 是从原始字符串中生成的新字符串,可以从中删去一些字符(可以是none),而不改变其余字符的相对顺序。 例如, “ace” 是 “abcde” 的子序列。 示例 1: 输入: s …

category

7

题型

code_blocks

4

代码语言

hub

3

相关题

当前训练重点

中等 · 数组·哈希·扫描

bolt

答案摘要

题目中字符串 的数据规模最高达到 $5 \times 10^4$,如果暴力枚举 中的每个字符串 ,判断其是否为 的子序列,很有可能会超时。 我们不妨将 中的所有单词根据首字母来分桶,即:把所有单词按照首字母分到 个桶中,每个桶中存储的是所有以该字母开头的所有单词。

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 数组·哈希·扫描 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给定字符串 s 和字符串数组 words, 返回  words[i] 中是s的子序列的单词个数 。

字符串的 子序列 是从原始字符串中生成的新字符串,可以从中删去一些字符(可以是none),而不改变其余字符的相对顺序。

  • 例如, “ace”“abcde” 的子序列。

 

示例 1:

输入: s = "abcde", words = ["a","bb","acd","ace"]
输出: 3
解释: 有三个是 s 的子序列的单词: "a", "acd", "ace"。

Example 2:

输入: s = "dsahjpjauf", words = ["ahjpjau","ja","ahbwzgqnuk","tnmlanowax"]
输出: 2

 

提示:

  • 1 <= s.length <= 5 * 104
  • 1 <= words.length <= 5000
  • 1 <= words[i].length <= 50
  • words[i]s 都只由小写字母组成。
​​​​
lightbulb

解题思路

方法一:分桶

题目中字符串 ss 的数据规模最高达到 5×1045 \times 10^4,如果暴力枚举 wordswords 中的每个字符串 ww,判断其是否为 ss 的子序列,很有可能会超时。

我们不妨将 wordswords 中的所有单词根据首字母来分桶,即:把所有单词按照首字母分到 2626 个桶中,每个桶中存储的是所有以该字母开头的所有单词。

比如对于 words = ["a", "bb", "acd", "ace"],我们得到以下的分桶结果:

a: ["a", "acd", "ace"]
b: ["bb"]

然后我们从 ss 的第一个字符开始遍历,假设当前字符为 'a',我们从 'a' 开头的桶中取出所有单词。对于取出的每个单词,如果此时单词长度为 11,说明该单词已经匹配完毕,我们将答案加 11;否则我们将单词的首字母去掉,然后放入下一个字母开头的桶中,比如对于单词 "acd",去掉首字母 'a' 后,我们将其放入 'c' 开头的桶中。这一轮结束后,分桶结果变为:

c: ["cd", "ce"]
b: ["bb"]

遍历完 ss 后,我们就得到了答案。

实际上,每个桶可以只存储单词的下标 ii 以及该单词当前匹配到的位置 jj,这样可以节省空间。

时间复杂度 O(n+i=0m1wi)O(n + \sum_{i=0}^{m-1} |w_i|),空间复杂度 O(m)O(m)。其中 nnmm 分别为 sswordswords 的长度,而 wi|w_i|words[i]words[i] 的长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution:
    def numMatchingSubseq(self, s: str, words: List[str]) -> int:
        d = defaultdict(deque)
        for w in words:
            d[w[0]].append(w)
        ans = 0
        for c in s:
            for _ in range(len(d[c])):
                t = d[c].popleft()
                if len(t) == 1:
                    ans += 1
                else:
                    d[t[1]].append(t[1:])
        return ans
speed

复杂度分析

指标
时间Depends on the final approach
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    The candidate demonstrates an understanding of subsequence matching and optimizes using hash maps or binary search.

  • question_mark

    The candidate is able to apply different data structures, such as hash maps, binary search, or tries, to optimize subsequence search.

  • question_mark

    The candidate is able to reduce time complexity efficiently and handle large input sizes within constraints.

warning

常见陷阱

外企场景
  • error

    Brute force checking of each word as a subsequence could lead to time complexity that exceeds the problem's limits.

  • error

    Not using an efficient data structure like a hash table or trie might result in slow performance for larger inputs.

  • error

    Overlooking edge cases where words might not match the sequence order in `s` or contain extra characters.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Use dynamic programming to store partial subsequences for more complex scenarios.

  • arrow_right_alt

    Instead of checking each word individually, preprocess the input string `s` to speed up subsequence checks.

  • arrow_right_alt

    Modify the approach to handle multiple strings where each has different character sets or sequences.

help

常见问题

外企场景

匹配子序列的单词数题解:数组·哈希·扫描 | LeetCode #792 中等