Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Index/双指针.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
| [719. 找出第 K 小的数对距离](https://leetcode.cn/problems/find-k-th-smallest-pair-distance/) | [LeetCode 题解链接](https://leetcode.cn/problems/find-k-th-smallest-pair-distance/solution/by-ac_oier-o4if/) | 困难 | 🤩🤩🤩🤩 |
| [777. 在LR字符串中交换相邻字符](https://leetcode.cn/problems/swap-adjacent-in-lr-string/) | [LeetCode 题解链接](https://leetcode.cn/problems/swap-adjacent-in-lr-string/solution/by-ac_oier-ye71/) | 中等 | 🤩🤩🤩🤩 |
| [786. 第 K 个最小的素数分数](https://leetcode-cn.com/problems/k-th-smallest-prime-fraction/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/k-th-smallest-prime-fraction/solution/gong-shui-san-xie-yi-ti-shuang-jie-you-x-8ymk/) | 中等 | 🤩🤩🤩 |
| [809. 情感丰富的文字](https://leetcode.cn/problems/expressive-words/) | [LeetCode 题解链接](https://leetcode.cn/problems/expressive-words/solution/by-ac_oier-tb57/) | 中等 | 🤩🤩🤩🤩🤩 |
| [825. 适龄的朋友](https://leetcode-cn.com/problems/friends-of-appropriate-ages/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/friends-of-appropriate-ages/solution/gong-shui-san-xie-yi-ti-shuang-jie-pai-x-maa8/) | 中等 | 🤩🤩🤩🤩 |
| [832. 翻转图像](https://leetcode-cn.com/problems/flipping-an-image/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/flipping-an-image/solution/shuang-zhi-zhen-yi-bian-chu-li-huan-you-ik0v1/) | 简单 | 🤩🤩 |
| [838. 推多米诺](https://leetcode-cn.com/problems/push-dominoes/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/push-dominoes/solution/gong-shui-san-xie-yi-ti-shuang-jie-bfs-y-z52w/) | 中等 | 🤩🤩🤩🤩 |
Expand Down
1 change: 1 addition & 0 deletions Index/模拟.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
| [796. 旋转字符串](https://leetcode-cn.com/problems/rotate-string/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/rotate-string/solution/by-ac_oier-bnkx/) | 简单 | 🤩🤩🤩 |
| [804. 唯一摩尔斯密码词](https://leetcode-cn.com/problems/unique-morse-code-words/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/unique-morse-code-words/solution/by-ac_oier-a9hv/) | 简单 | 🤩🤩🤩 |
| [806. 写字符串需要的行数](https://leetcode-cn.com/problems/number-of-lines-to-write-string/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/number-of-lines-to-write-string/solution/by-ac_oier-5hg2/) | 简单 | 🤩🤩🤩🤩 |
| [809. 情感丰富的文字](https://leetcode.cn/problems/expressive-words/) | [LeetCode 题解链接](https://leetcode.cn/problems/expressive-words/solution/by-ac_oier-tb57/) | 中等 | 🤩🤩🤩🤩 |
| [811. 子域名访问计数](https://leetcode.cn/problems/subdomain-visit-count/) | [LeetCode 题解链接](https://leetcode.cn/problems/subdomain-visit-count/solution/by-ac_oier-aex6/) | 中等 | 🤩🤩🤩🤩 |
| [812. 最大三角形面积](https://leetcode.cn/problems/largest-triangle-area/) | [LeetCode 题解链接](https://leetcode.cn/problems/largest-triangle-area/solution/by-ac_oier-htv8/) | 简单 | 🤩🤩🤩🤩 |
| [816. 模糊坐标](https://leetcode.cn/problems/ambiguous-coordinates/) | [LeetCode 题解链接](https://leetcode.cn/problems/ambiguous-coordinates/solution/by-ac_oier-sbxl/) | 中等 | 🤩🤩🤩🤩 |
Expand Down
131 changes: 131 additions & 0 deletions LeetCode/801-810/809. 情感丰富的文字(中等).md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
### 题目描述

这是 LeetCode 上的 **[809. 情感丰富的文字](https://leetcode.cn/problems/expressive-words/solution/by-ac_oier-tb57/)** ,难度为 **中等**。

Tag : 「双指针」、「模拟」



有时候人们会用重复写一些字母来表示额外的感受,比如 `"hello" -> "heeellooo", "hi" -> "hiii"`。我们将相邻字母都相同的一串字符定义为相同字母组,例如:`"h", "eee", "ll", "ooo"`。

对于一个给定的字符串 `S` ,如果另一个单词能够通过将一些字母组扩张从而使其和 `S` 相同,我们将这个单词定义为可扩张的(`stretchy`)。扩张操作定义如下:选择一个字母组(包含字母 `c` ),然后往其中添加相同的字母 `c` 使其长度达到 `3` 或以上。

例如,以 `"hello"` 为例,我们可以对字母组 `"o"` 扩张得到 `"hellooo"`,但是无法以同样的方法得到 `"helloo"` 因为字母组 `"oo"` 长度小于 `3`。此外,我们可以进行另一种扩张 `"ll" -> "lllll"` 以获得 `"helllllooo"`。如果 `S = "helllllooo"`,那么查询词 `"hello"` 是可扩张的,因为可以对它执行这两种扩张操作使得 `query = "hello" -> "hellooo" -> "helllllooo" = S`。

输入一组查询单词,输出其中可扩张的单词数量。

示例:
```
输入:
S = "heeellooo"
words = ["hello", "hi", "helo"]

输出:1

解释:
我们能通过扩张 "hello" 的 "e" 和 "o" 来得到 "heeellooo"。
我们不能通过扩张 "helo" 来得到 "heeellooo" 因为 "ll" 的长度小于 3 。
```

提示:
* $0 <= len(S) <= 100$
* $0 <= len(words) <= 100$
* $0 <= len(words[i]) <= 100$
* `S` 和所有在 `words` 中的单词都只由小写字母组成。

---

### 双指针

该题最难的部分就是理解 “扩张” 操作:假设有两个字符相同的连续段 `a` 和 `b`,如何判断 `a` 是否能由 `b` 扩张而来。

忘记掉题目所说的规则,我们重新定义 “扩张” 操作:

* 当 `a` 和 `b` 长度相同,定义为可扩张;
* 当 `a` 和 `b` 长度不同,根据「`a` 和 `b` 长度对比」以及「`a` 的长度大小」分情况讨论:
* 当 `b` 长度大于 `a`,不可扩张;
* 当 `a` 长度大于 `b`,**我们不一定要拿整一段的 `b` 进行扩张,可以拿 `b` 中的一个字符进行扩张。** 因此只需要满足扩张后的长度(`a` 的长度)大于 $3$ 即可定义为可扩张。

搞明白何为 “扩张” 后,剩余的则是简单的「双指针 + 模拟」做法。

Java 代码:
```Java
class Solution {
public int expressiveWords(String s, String[] words) {
int n = s.length(), ans = 0;
out:for (String word : words) {
int m = word.length(), i = 0, j = 0;
while (i < n && j < m) {
if (s.charAt(i) != word.charAt(j)) continue out;
int a = i, b = j;
while (a < n && s.charAt(a) == s.charAt(i)) a++;
while (b < m && word.charAt(b) == word.charAt(j)) b++;
a -= i; b -= j;
if (a != b && (b > a || a < 3)) continue out;
i += a; j += b;
}
if (i == n && j == m) ans++;
}
return ans;
}
}
```
TypeScript 代码:
```TypeScript
function expressiveWords(s: string, words: string[]): number {
let n = s.length, ans = 0
out:for (const word of words) {
let m = word.length, i = 0, j = 0
while (i < n && j < m) {
if (s[i] != word[j]) continue out
let a = i, b = j
while (a < n && s[a] == s[i]) a++
while (b < m && word[b] == word[j]) b++
a -= i; b -= j;
if (a != b && (b > a || a < 3)) continue out
i += a; j += b;
}
if (i == n && j == m) ans++;
}
return ans
}
```
Python 代码:
```Python
class Solution:
def expressiveWords(self, s: str, words: List[str]) -> int:
n, ans = len(s), 0
for word in words:
m, i, j = len(word), 0, 0
ok = True
while ok and i < n and j < m:
if s[i] != word[j]:
ok = False
a, b = i, j
while a < n and s[a] == s[i]:
a += 1
while b < m and word[b] == word[j]:
b += 1
a, b = a - i, b - j
if a != b and (b > a or a < 3):
ok = False
i, j = i + a, j + b
if ok and i == n and j == m:
ans += 1
return ans
```
* 时间复杂度:$O(n \times m + \sum_{i = 0}^{m - 1}words[i].length)$,其中 `n` 为字符串 `s` 的长度,`m` 为数组 `words` 的长度
* 空间复杂度:$O(1)$

---

### 最后

这是我们「刷穿 LeetCode」系列文章的第 `No.809` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。

在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。

为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。

在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。