forked from azl397985856/leetcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
lucifer
committed
Jan 22, 2020
1 parent
f36fd58
commit b8e8fa5
Showing
5 changed files
with
315 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
168 changes: 168 additions & 0 deletions
168
problems/211.add-and-search-word-data-structure-design.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
## 题目地址(211. 添加与搜索单词 - 数据结构设计) | ||
|
||
https://leetcode-cn.com/problems/add-and-search-word-data-structure-design/description/ | ||
|
||
## 题目描述 | ||
|
||
``` | ||
设计一个支持以下两种操作的数据结构: | ||
void addWord(word) | ||
bool search(word) | ||
search(word) 可以搜索文字或正则表达式字符串,字符串只包含字母 . 或 a-z 。 . 可以表示任何一个字母。 | ||
示例: | ||
addWord("bad") | ||
addWord("dad") | ||
addWord("mad") | ||
search("pad") -> false | ||
search("bad") -> true | ||
search(".ad") -> true | ||
search("b..") -> true | ||
说明: | ||
你可以假设所有单词都是由小写字母 a-z 组成的。 | ||
``` | ||
|
||
## 思路 | ||
|
||
我们首先不考虑字符"."的情况。这种情况比较简单,我们 addWord 直接添加到数组尾部,search 则线性查找即可。 | ||
|
||
接下来我们考虑特殊字符“.”,其实也不难,只不过 search 的时候,判断如果是“.”, 我们认为匹配到了,继续往后匹配即可。 | ||
|
||
上面的代码复杂度会比较高,我们考虑优化。如果你熟悉前缀树的话,应该注意到这可以使用前缀树来进行优化。前缀树优化之后每次查找复杂度是$O(h)$, 其中 h 是前缀树深度,也就是最长的字符串长度。 | ||
|
||
关于前缀树,LeetCode 有很多题目。有的是直接考察,让你实现一个前缀树,有的是间接考察,比如本题。前缀树代码见下方,大家之后可以直接当成前缀树的解题模板使用。 | ||
|
||
由于我们这道题需要考虑特殊字符".",因此我们需要对标准前缀树做一点改造,insert 不做改变,我们只需要改变 search 即可,代码(Python 3): | ||
|
||
```python | ||
def search(self, word): | ||
""" | ||
Returns if the word is in the trie. | ||
:type word: str | ||
:rtype: bool | ||
""" | ||
curr = self.Trie | ||
for i, w in enumerate(word): | ||
if w == '.': | ||
wizards = [] | ||
for k in curr.keys(): | ||
if k == '#': | ||
continue | ||
wizards.append(self.search(word[:i] + k + word[i + 1:])) | ||
return any(wizards) | ||
if w not in curr: | ||
return False | ||
curr = curr[w] | ||
return "#" in curr | ||
``` | ||
|
||
标准的前缀树搜索我也贴一下代码,大家可以对比一下: | ||
|
||
```python | ||
def search(self, word): | ||
""" | ||
Returns if the word is in the trie. | ||
:type word: str | ||
:rtype: bool | ||
""" | ||
curr = self.Trie | ||
for w in word: | ||
if w not in curr: | ||
return False | ||
curr = curr[w] | ||
return "#" in curr | ||
``` | ||
|
||
## 关键点 | ||
|
||
- 前缀树(也叫字典树),英文名 Trie(读作 tree 或者 try) | ||
|
||
## 代码 | ||
|
||
- 语言支持:Python3 | ||
|
||
Python3 Code: | ||
|
||
关于 Trie 的代码: | ||
|
||
```python | ||
class Trie: | ||
|
||
def __init__(self): | ||
""" | ||
Initialize your data structure here. | ||
""" | ||
self.Trie = {} | ||
|
||
def insert(self, word): | ||
""" | ||
Inserts a word into the trie. | ||
:type word: str | ||
:rtype: void | ||
""" | ||
curr = self.Trie | ||
for w in word: | ||
if w not in curr: | ||
curr[w] = {} | ||
curr = curr[w] | ||
curr['#'] = 1 | ||
|
||
def search(self, word): | ||
""" | ||
Returns if the word is in the trie. | ||
:type word: str | ||
:rtype: bool | ||
""" | ||
curr = self.Trie | ||
for i, w in enumerate(word): | ||
if w == '.': | ||
wizards = [] | ||
for k in curr.keys(): | ||
if k == '#': | ||
continue | ||
wizards.append(self.search(word[:i] + k + word[i + 1:])) | ||
return any(wizards) | ||
if w not in curr: | ||
return False | ||
curr = curr[w] | ||
return "#" in curr | ||
``` | ||
|
||
主逻辑代码: | ||
|
||
```python | ||
class WordDictionary: | ||
|
||
def __init__(self): | ||
""" | ||
Initialize your data structure here. | ||
""" | ||
self.trie = Trie() | ||
|
||
def addWord(self, word: str) -> None: | ||
""" | ||
Adds a word into the data structure. | ||
""" | ||
self.trie.insert(word) | ||
|
||
def search(self, word: str) -> bool: | ||
""" | ||
Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. | ||
""" | ||
return self.trie.search(word) | ||
|
||
|
||
# Your WordDictionary object will be instantiated and called as such: | ||
# obj = WordDictionary() | ||
# obj.addWord(word) | ||
# param_2 = obj.search(word) | ||
``` | ||
|
||
## 相关题目 | ||
|
||
- [208.implement-trie-prefix-tree](./208.implement-trie-prefix-tree.md) | ||
- [212.word-search-ii](./212.word-search-ii.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
## 题目地址(212. 单词搜索 II) | ||
|
||
https://leetcode-cn.com/problems/word-search-ii/description/ | ||
|
||
## 题目描述 | ||
|
||
``` | ||
给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。 | ||
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。 | ||
示例: | ||
输入: | ||
words = ["oath","pea","eat","rain"] and board = | ||
[ | ||
['o','a','a','n'], | ||
['e','t','a','e'], | ||
['i','h','k','r'], | ||
['i','f','l','v'] | ||
] | ||
输出: ["eat","oath"] | ||
说明: | ||
你可以假设所有输入都由小写字母 a-z 组成。 | ||
提示: | ||
你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯? | ||
如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。 | ||
``` | ||
|
||
## 思路 | ||
|
||
我们需要对矩阵中每一项都进行深度优先遍历(DFS)。 递归的终点是 | ||
|
||
- 1. 超出边界 | ||
- 2. 递归路径上组成的单词不在 words 的前缀。 | ||
|
||
比如题目示例:words = ["oath","pea","eat","rain"],那么对于 oa,oat 满足条件,因为他们都是 oath 的前缀,但是 oaa 就不满足条件。 | ||
|
||
为了防止环的出现,我们需要记录访问过的节点。而返回结果是需要去重的。出于简单考虑,我们使用集合(set),最后返回的时候重新转化为 list。 | ||
|
||
刚才我提到了一个关键词“前缀”,我们考虑使用前缀树来优化。使得复杂度降低为$O(h)$, 其中 h 是前缀树深度,也就是最长的字符串长度。 | ||
|
||
## 关键点 | ||
|
||
- 前缀树(也叫字典树),英文名 Trie(读作 tree 或者 try) | ||
- DFS | ||
- hashmap 结合 dfs 记录访问过的元素的时候,注意结束之后需要将 hashmap 的值重置。(下方代码的`del seen[(i, j)]`) | ||
|
||
## 代码 | ||
|
||
- 语言支持:Python3 | ||
|
||
Python3 Code: | ||
|
||
关于 Trie 的代码: | ||
|
||
```python | ||
class Trie: | ||
|
||
def __init__(self): | ||
""" | ||
Initialize your data structure here. | ||
""" | ||
self.Trie = {} | ||
|
||
def insert(self, word): | ||
""" | ||
Inserts a word into the trie. | ||
:type word: str | ||
:rtype: void | ||
""" | ||
curr = self.Trie | ||
for w in word: | ||
if w not in curr: | ||
curr[w] = {} | ||
curr = curr[w] | ||
curr['#'] = 1 | ||
|
||
def startsWith(self, prefix): | ||
""" | ||
Returns if there is any word in the trie that starts with the given prefix. | ||
:type prefix: str | ||
:rtype: bool | ||
""" | ||
|
||
curr = self.Trie | ||
for w in prefix: | ||
if w not in curr: | ||
return False | ||
curr = curr[w] | ||
return True | ||
``` | ||
|
||
主逻辑代码: | ||
|
||
```python | ||
class Solution: | ||
def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: | ||
m = len(board) | ||
if m == 0: | ||
return [] | ||
n = len(board[0]) | ||
trie = Trie() | ||
seen = None | ||
res = set() | ||
for word in words: | ||
trie.insert(word) | ||
|
||
def dfs(s, i, j): | ||
if (i, j) in seen or i < 0 or i >= m or j < 0 or j >= n or not trie.startsWith(s): | ||
return | ||
s += board[i][j] | ||
seen[(i, j)] = True | ||
|
||
if s in words: | ||
res.add(s) | ||
dfs(s, i + 1, j) | ||
dfs(s, i - 1, j) | ||
dfs(s, i, j + 1) | ||
dfs(s, i, j - 1) | ||
|
||
del seen[(i, j)] | ||
|
||
for i in range(m): | ||
for j in range(n): | ||
seen = dict() | ||
dfs("", i, j) | ||
return list(res) | ||
``` | ||
|
||
## 相关题目 | ||
|
||
- [208.implement-trie-prefix-tree](./208.implement-trie-prefix-tree.md) | ||
- [211.add-and-search-word-data-structure-design](./211.add-and-search-word-data-structure-design.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters