Skip to content

Commit

Permalink
feat: 前缀树专题
Browse files Browse the repository at this point in the history
  • Loading branch information
lucifer committed Feb 4, 2020
1 parent 2057b5e commit 1d86136
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 2 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,18 +265,20 @@ leetcode 题解,记录自己的 leetcode 解题之路。
- [0301.remove-invalid-parentheses](./problems/301.remove-invalid-parentheses.md)
- [0335.self-crossPing](./problems/335.self-crossing.md) 🆕
- [0460.lfu-cache](./problems/460.lfu-cache.md) 🆕
- [0472.concatenated-words](./problems/472.concatenated-words.md) 🆕
- [0493.reverse-pairs](./problems/493.reverse-pairs.md) 🆕
- [1168.optimize-water-distribution-in-a-village](./problems/1168.optimize-water-distribution-in-a-village-cn.md) 🆕

### 数据结构与算法的总结

- [数据结构](./thinkings/basic-data-structure.md)(草稿)
- [基础算法](./thinkings/basic-algorithm.md)(草稿)
- [数据结构](./thinkings/basic-data-structure.md)
- [基础算法](./thinkings/basic-algorithm.md)
- [二叉树的遍历](./thinkings/binary-tree-traversal.md)
- [动态规划](./thinkings/dynamic-programming.md)
- [哈夫曼编码和游程编码](./thinkings/run-length-encode-and-huffman-encode.md)
- [布隆过滤器](./thinkings/bloom-filter.md)
- [字符串问题](./thinkings/string-problems.md)
- [前缀树专题](./thinkings/trie.md) 🆕

### anki 卡片

Expand Down
1 change: 1 addition & 0 deletions problems/208.implement-trie-prefix-tree.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,4 @@ Trie.prototype.startsWith = function(prefix) {

- [211.add-and-search-word-data-structure-design](./211.add-and-search-word-data-structure-design.md)
- [212.word-search-ii](./212.word-search-ii.md)
- [472.concatenated-words](./problems/472.concatenated-words.md)
1 change: 1 addition & 0 deletions problems/211.add-and-search-word-data-structure-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,4 @@ class WordDictionary:

- [208.implement-trie-prefix-tree](./208.implement-trie-prefix-tree.md)
- [212.word-search-ii](./212.word-search-ii.md)
- [472.concatenated-words](./problems/472.concatenated-words.md)
1 change: 1 addition & 0 deletions problems/212.word-search-ii.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,4 @@ class Solution:

- [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)
- [472.concatenated-words](./problems/472.concatenated-words.md)
121 changes: 121 additions & 0 deletions problems/472.concatenated-words.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
## 题目地址(472. 连接词)

https://leetcode-cn.com/problems/concatenated-words/

## 题目描述

```
给定一个不含重复单词的列表,编写一个程序,返回给定单词列表中所有的连接词。
连接词的定义为:一个字符串完全是由至少两个给定数组中的单词组成的。
示例:
输入: ["cat","cats","catsdogcats","dog","dogcatsdog","hippopotamuses","rat","ratcatdogcat"]
输出: ["catsdogcats","dogcatsdog","ratcatdogcat"]
解释: "catsdogcats"由"cats", "dog" 和 "cats"组成;
"dogcatsdog"由"dog", "cats"和"dog"组成;
"ratcatdogcat"由"rat", "cat", "dog"和"cat"组成。
说明:
给定数组的元素总数不超过 10000。
给定数组中元素的长度总和不超过 600000。
所有输入字符串只包含小写字母。
不需要考虑答案输出的顺序。
```

## 思路

本题我的思路是直接使用前缀树来解决。**标准的前缀树模板**我在之前的题解中提到了,感兴趣的可以到下方的相关题目中查看。

这道题这里我们不需要 search,我们的做法是:

- 先进行一次遍历,将 words 全部插入(insert)到前缀树中。
- 然后再进行一次遍历,查找每一个单词有几个单词表中的单词组成
- 如果大于 2,则将其加入到 res 中
- 最后返回 res 即可

我们构造的前缀树大概是这样的:

![472.concatenated-words.png](http://ww1.sinaimg.cn/large/e9f490c8ly1gbkcox4r06j21eb15fgq8.jpg)

问题的关键在于第二步中的**查找每一个单词有几个单词表中的单词组成**。 其实如果你了解前缀树的话应该不难写出来。 比如查找 catsdogcats:

- 我们先从 c 到 a 到 t,发现 t 是单词结尾,我们数量 + 1
- 然后将剩下的部分“sdogcats”重新执行上述过程。
- s 发现找不到,我们返回 0
- 因此最终结果是 1

很明显这个逻辑是错误的,正确的划分应该是:

- 我们先从 c 到 a 到 t,再到 s,此时数量 + 1
- 然后将剩下的“dogcats”重复上述过程
- dog 找到了,数量 + 1
- 最后将 cats 加入。也找到了,数量再加 1

由于我们并不知道 cat 这里断开,结果更大?还是 cats 这里断开结果更大?因此我们的做法是将其全部递归求出,然后取出最大值即可。如果我们直接这样递归的话,可能会超时,卡在最后一个测试用例上。一个简单的方式是记忆化递归,从而避免重复计算,经测试这种方法能够通过。

## 代码

代码支持:Python3

Python3 Code:

```python
class Trie:

def __init__(self):
self.Trie = {}
self.visited = {}

def insert(self, word):
curr = self.Trie
for w in word:
if w not in curr:
curr[w] = {}
curr = curr[w]
curr['#'] = 1

def cntWords(self, word):
if not word:
return 0
if word in self.visited:
return self.visited[word]
curr = self.Trie
res = float('-inf')

for i, w in enumerate(word):
if w not in curr:
return res
curr = curr[w]
if '#' in curr:
res = max(res, 1 + self.cntWords(word[i + 1:]))
self.visited[word] = res
return res


class Solution:
def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]:
self.trie = Trie()
res = []

for word in words:
self.trie.insert(word)
for word in words:
if self.trie.cntWords(word) >= 2:
res.append(word)
return res
```

## 关键点分析

- 前缀树

## 相关题目

- [208.implement-trie-prefix-tree](https://github.com/azl397985856/leetcode/blob/b8e8fa5f0554926efa9039495b25ed7fc158372a/problems/208.implement-trie-prefix-tree.md)
- [211.add-and-search-word-data-structure-design](https://github.com/azl397985856/leetcode/blob/b0b69f8f11dace3a9040b54532105d42e88e6599/problems/211.add-and-search-word-data-structure-design.md)
- [212.word-search-ii](https://github.com/azl397985856/leetcode/blob/b0b69f8f11dace3a9040b54532105d42e88e6599/problems/212.word-search-ii.md)
- [0472.concatenated-words](./problems/472.concatenated-words.md)
26 changes: 26 additions & 0 deletions thinkings/trie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## 前缀树问题

截止目前(2020-02-04) [前缀树(字典树)](https://leetcode-cn.com/tag/trie/) 在 LeetCode 一共有 17 道题目。其中 2 道简单,8 个中等,7 个困难。

这里总结了四道题,弄懂这几道, 那么前缀树对你应该不是大问题, 希望这个专题可以帮到正在学习前缀树 的你。

前缀树的 api 主要有以下几个:

- `insert(word)`: 插入一个单词
- `search(word)`:查找一个单词是否存在
- `startWith(word)`: 查找是否存在以 word 为前缀的单词

其中 startWith 是前缀树最核心的用法,其名称前缀树就从这里而来。大家可以先拿 208 题开始,熟悉一下前缀树,然后再尝试别的题目。

一个前缀树大概是这个样子:

![](https://github.com/azl397985856/leetcode/raw/b8e8fa5f0554926efa9039495b25ed7fc158372a/assets/problems/208.implement-trie-prefix-tree-1.png)

如图每一个节点存储一个字符,然后外加一个控制信息表示是否是单词结尾,实际使用过程可能会有细微差别,不过变化不大。

以下是本专题的四道题目的题解,内容会持续更新,感谢你的关注~

- [208.implement-trie-prefix-tree](https://github.com/azl397985856/leetcode/blob/b8e8fa5f0554926efa9039495b25ed7fc158372a/problems/208.implement-trie-prefix-tree.md)
- [211.add-and-search-word-data-structure-design](https://github.com/azl397985856/leetcode/blob/b0b69f8f11dace3a9040b54532105d42e88e6599/problems/211.add-and-search-word-data-structure-design.md)
- [212.word-search-ii](https://github.com/azl397985856/leetcode/blob/b0b69f8f11dace3a9040b54532105d42e88e6599/problems/212.word-search-ii.md)
- [472.concatenated-words](https://github.com/azl397985856/leetcode/blob/master/problems/472.concatenated-words.md)

0 comments on commit 1d86136

Please sign in to comment.