Skip to content

Commit 4d070df

Browse files
author
lucifer
committed
fix: typo
1 parent 8daf8ba commit 4d070df

File tree

1 file changed

+19
-11
lines changed

1 file changed

+19
-11
lines changed

problems/1178.number-of-valid-words-for-each-puzzle.md

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class Solution:
8383
return ans
8484
```
8585

86-
由于这种做法需要遍历 puzzbles 和 words 的所有组合,因此时间复杂不低于是 $O(m * n)$,其中 m 和 n 分别为 words 和 puzzbles 的长度。看下题目的约束条件:
86+
由于这种做法需要遍历 puzzles 和 words 的所有组合,因此时间复杂不低于是 $O(m * n)$,其中 m 和 n 分别为 words 和 puzzles 的长度。看下题目的约束条件:
8787

8888
```
8989
1 <= words.length <= 10^5
@@ -102,12 +102,12 @@ puzzles[i].length == 7
102102

103103
基本可以锁定为是**状态压缩**。力扣相关的题目很多,基本都是有一个约束条件的数据范围很小(比如 20 以内)。我们要做的通常就是**给这个小的变量做状态压缩**
104104

105-
这道题的关键其实就是**单词  word  中的每一个字母都可以在谜面  puzzle  中找到**,所有的重复计算都是基于此产生的。这句话的含义其实就是**word 中字符组成的集合是 puzzble 中组成的集合的子集**
105+
这道题的关键其实就是**单词  word  中的每一个字母都可以在谜面  puzzle  中找到**,所有的重复计算都是基于此产生的。这句话的含义其实就是**word 中字符组成的集合是 puzzle 中组成的集合的子集**
106106

107107
基于上面两条重要信息,我们可以初步锁定算法为:
108108

109109
- 用二进制表示 puzzle
110-
- 枚举 puzzble 的所有子集(二进制子集枚举)
110+
- 枚举 puzzle 的所有子集(二进制子集枚举)
111111
- 判断所有子集 j 是否在 words 中出现过。如果出现过,则将计数器累加出现的次数。这提示我们同样将 word 使用二进制进行存储。虽然 words[i] 的长度范围比较大([4,50]),但我们关心的其实是**去重的子集**。注意到 words[i] 的取值范围是小写字符,因此这个范围不大于 26,使用 int 存储完全够了。
112112

113113
枚举二进制子集是一个常见的操作,竞赛中也不时出现,大家可以阅读相关内容,具体原理不再展开。
@@ -129,18 +129,18 @@ class Solution:
129129
counts = collections.defaultdict(int)
130130
ans = [0] * len(puzzles)
131131
for word in words:
132-
bit = 0
132+
bit = 0 # bit 是 word 的二进制表示
133133
for c in word:
134134
bit |= 1 << ord(c) - ord("a")
135135
counts[bit] += 1
136136
for i, puzzle in enumerate(puzzles):
137-
bit = 0
137+
bit = 0 # bit 是 puzzle 的二进制表示
138138
for c in puzzle:
139139
bit |= 1 << ord(c) - ord("a")
140-
j = bit
140+
j = bit # j 是 bit 的子集
141141
# 倒序枚举 bit 的子集 j
142142
while j:
143-
# 单词 word 需要保护谜面的第一个字母
143+
# 单词 word 需要包含谜面的第一个字母
144144
if 1 << ord(puzzle[0]) - ord("a") & j:
145145
ans[i] += counts[j]
146146
j = bit & (j - 1)
@@ -161,14 +161,22 @@ class Solution:
161161

162162
看了官方的解答还提供了字典树的解法。于是我也用字典树实现了一遍。
163163

164-
之所以使用字典树可以是因为只关心
164+
之所以可以使用字典树求解是因为我们只关心
165165

166-
- word 是否是 puzzble 的子集
166+
- word 是否是 puzzle 的子集
167167
- 如果是,则关心 word 出现的次数
168168

169-
但由于类似:words: ["abc", "acb", "bac"] 等的存在,使得判断的时间大大增加,如果进行一次排序,此时 words 为:["abc", "abc", "abc"]这对我们来说就减少的判断,而这**对于我们求的答案来说是等价的**。。除此之外,word 中一个字符出现几次对我们来说是一样的。比如 words: ["abc", "aaaaabbbc"] 可以看成是 ["abc", "abc"]**对于我们求的答案来说是等价的**
169+
但由于类似:words: ["abc", "acb", "bac"] 等的存在,使得判断的时间大大增加,如果进行一次排序,此时 words 为:["abc", "abc", "abc"]而如果统计排序后相同 word 出现的次数,比如:
170170

171-
因此我们可以将其进行一次**排序并去重**。同理,我们需要对 puzzble 进行排序并去重。而由于题目规定了 puzzle 本身不含重复字符,因此只对 puzzble 进行排序也是可以的。
171+
```py
172+
{
173+
"abc": 3
174+
}
175+
```
176+
177+
这就可以仅判断一次而不是多次了,这就减少了判断。而这**对于我们求的答案来说是等价的**。除此之外,word 中一个字符出现几次对我们来说是一样的。比如 words: ["abc", "aaaaabbbc"] 可以看成是 ["abc", "abc"]**对于我们求的答案来说是等价的**
178+
179+
因此我们可以将其进行一次**排序并去重**。同理,我们需要对 puzzle 进行排序并去重。而由于题目规定了 puzzle 本身不含重复字符,因此只对 puzzle 进行排序也是可以的。
172180

173181
这种做法同样需要枚举 puzzle 的子集。伪代码:
174182

0 commit comments

Comments
 (0)