|
| 1 | +### 题目描述 |
| 2 | + |
| 3 | +这是 LeetCode 上的 **[809. 情感丰富的文字](https://leetcode.cn/problems/expressive-words/solution/by-ac_oier-tb57/)** ,难度为 **中等**。 |
| 4 | + |
| 5 | +Tag : 「双指针」、「模拟」 |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +有时候人们会用重复写一些字母来表示额外的感受,比如 `"hello" -> "heeellooo", "hi" -> "hiii"`。我们将相邻字母都相同的一串字符定义为相同字母组,例如:`"h", "eee", "ll", "ooo"`。 |
| 10 | + |
| 11 | +对于一个给定的字符串 `S` ,如果另一个单词能够通过将一些字母组扩张从而使其和 `S` 相同,我们将这个单词定义为可扩张的(`stretchy`)。扩张操作定义如下:选择一个字母组(包含字母 `c` ),然后往其中添加相同的字母 `c` 使其长度达到 `3` 或以上。 |
| 12 | + |
| 13 | +例如,以 `"hello"` 为例,我们可以对字母组 `"o"` 扩张得到 `"hellooo"`,但是无法以同样的方法得到 `"helloo"` 因为字母组 `"oo"` 长度小于 `3`。此外,我们可以进行另一种扩张 `"ll" -> "lllll"` 以获得 `"helllllooo"`。如果 `S = "helllllooo"`,那么查询词 `"hello"` 是可扩张的,因为可以对它执行这两种扩张操作使得 `query = "hello" -> "hellooo" -> "helllllooo" = S`。 |
| 14 | + |
| 15 | +输入一组查询单词,输出其中可扩张的单词数量。 |
| 16 | + |
| 17 | +示例: |
| 18 | +``` |
| 19 | +输入: |
| 20 | +S = "heeellooo" |
| 21 | +words = ["hello", "hi", "helo"] |
| 22 | +
|
| 23 | +输出:1 |
| 24 | +
|
| 25 | +解释: |
| 26 | +我们能通过扩张 "hello" 的 "e" 和 "o" 来得到 "heeellooo"。 |
| 27 | +我们不能通过扩张 "helo" 来得到 "heeellooo" 因为 "ll" 的长度小于 3 。 |
| 28 | +``` |
| 29 | + |
| 30 | +提示: |
| 31 | +* $0 <= len(S) <= 100$ |
| 32 | +* $0 <= len(words) <= 100$ |
| 33 | +* $0 <= len(words[i]) <= 100$ |
| 34 | +* `S` 和所有在 `words` 中的单词都只由小写字母组成。 |
| 35 | + |
| 36 | +--- |
| 37 | + |
| 38 | +### 双指针 |
| 39 | + |
| 40 | +该题最难的部分就是理解 “扩张” 操作:假设有两个字符相同的连续段 `a` 和 `b`,如何判断 `a` 是否能由 `b` 扩张而来。 |
| 41 | + |
| 42 | +忘记掉题目所说的规则,我们重新定义 “扩张” 操作: |
| 43 | + |
| 44 | +* 当 `a` 和 `b` 长度相同,定义为可扩张; |
| 45 | +* 当 `a` 和 `b` 长度不同,根据「`a` 和 `b` 长度对比」以及「`a` 的长度大小」分情况讨论: |
| 46 | + * 当 `b` 长度大于 `a`,不可扩张; |
| 47 | + * 当 `a` 长度大于 `b`,**我们不一定要拿整一段的 `b` 进行扩张,可以拿 `b` 中的一个字符进行扩张。** 因此只需要满足扩张后的长度(`a` 的长度)大于 $3$ 即可定义为可扩张。 |
| 48 | + |
| 49 | +搞明白何为 “扩张” 后,剩余的则是简单的「双指针 + 模拟」做法。 |
| 50 | + |
| 51 | +Java 代码: |
| 52 | +```Java |
| 53 | +class Solution { |
| 54 | + public int expressiveWords(String s, String[] words) { |
| 55 | + int n = s.length(), ans = 0; |
| 56 | + out:for (String word : words) { |
| 57 | + int m = word.length(), i = 0, j = 0; |
| 58 | + while (i < n && j < m) { |
| 59 | + if (s.charAt(i) != word.charAt(j)) continue out; |
| 60 | + int a = i, b = j; |
| 61 | + while (a < n && s.charAt(a) == s.charAt(i)) a++; |
| 62 | + while (b < m && word.charAt(b) == word.charAt(j)) b++; |
| 63 | + a -= i; b -= j; |
| 64 | + if (a != b && (b > a || a < 3)) continue out; |
| 65 | + i += a; j += b; |
| 66 | + } |
| 67 | + if (i == n && j == m) ans++; |
| 68 | + } |
| 69 | + return ans; |
| 70 | + } |
| 71 | +} |
| 72 | +``` |
| 73 | +TypeScript 代码: |
| 74 | +```TypeScript |
| 75 | +function expressiveWords(s: string, words: string[]): number { |
| 76 | + let n = s.length, ans = 0 |
| 77 | + out:for (const word of words) { |
| 78 | + let m = word.length, i = 0, j = 0 |
| 79 | + while (i < n && j < m) { |
| 80 | + if (s[i] != word[j]) continue out |
| 81 | + let a = i, b = j |
| 82 | + while (a < n && s[a] == s[i]) a++ |
| 83 | + while (b < m && word[b] == word[j]) b++ |
| 84 | + a -= i; b -= j; |
| 85 | + if (a != b && (b > a || a < 3)) continue out |
| 86 | + i += a; j += b; |
| 87 | + } |
| 88 | + if (i == n && j == m) ans++; |
| 89 | + } |
| 90 | + return ans |
| 91 | +} |
| 92 | +``` |
| 93 | +Python 代码: |
| 94 | +```Python |
| 95 | +class Solution: |
| 96 | + def expressiveWords(self, s: str, words: List[str]) -> int: |
| 97 | + n, ans = len(s), 0 |
| 98 | + for word in words: |
| 99 | + m, i, j = len(word), 0, 0 |
| 100 | + ok = True |
| 101 | + while ok and i < n and j < m: |
| 102 | + if s[i] != word[j]: |
| 103 | + ok = False |
| 104 | + a, b = i, j |
| 105 | + while a < n and s[a] == s[i]: |
| 106 | + a += 1 |
| 107 | + while b < m and word[b] == word[j]: |
| 108 | + b += 1 |
| 109 | + a, b = a - i, b - j |
| 110 | + if a != b and (b > a or a < 3): |
| 111 | + ok = False |
| 112 | + i, j = i + a, j + b |
| 113 | + if ok and i == n and j == m: |
| 114 | + ans += 1 |
| 115 | + return ans |
| 116 | +``` |
| 117 | +* 时间复杂度:$O(n \times m + \sum_{i = 0}^{m - 1}words[i].length)$,其中 `n` 为字符串 `s` 的长度,`m` 为数组 `words` 的长度 |
| 118 | +* 空间复杂度:$O(1)$ |
| 119 | + |
| 120 | +--- |
| 121 | + |
| 122 | +### 最后 |
| 123 | + |
| 124 | +这是我们「刷穿 LeetCode」系列文章的第 `No.809` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 |
| 125 | + |
| 126 | +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 |
| 127 | + |
| 128 | +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 |
| 129 | + |
| 130 | +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 |
| 131 | + |
0 commit comments