diff --git a/README.md b/README.md index f6d8feed4..37c9de13e 100644 --- a/README.md +++ b/README.md @@ -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 卡片 diff --git a/problems/208.implement-trie-prefix-tree.md b/problems/208.implement-trie-prefix-tree.md index 9b87f68e8..73d153896 100644 --- a/problems/208.implement-trie-prefix-tree.md +++ b/problems/208.implement-trie-prefix-tree.md @@ -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) diff --git a/problems/211.add-and-search-word-data-structure-design.md b/problems/211.add-and-search-word-data-structure-design.md index a11a1b332..f275a7a66 100644 --- a/problems/211.add-and-search-word-data-structure-design.md +++ b/problems/211.add-and-search-word-data-structure-design.md @@ -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) diff --git a/problems/212.word-search-ii.md b/problems/212.word-search-ii.md index 951dfe639..26affa133 100644 --- a/problems/212.word-search-ii.md +++ b/problems/212.word-search-ii.md @@ -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) diff --git a/problems/472.concatenated-words.md b/problems/472.concatenated-words.md new file mode 100644 index 000000000..4475cfbae --- /dev/null +++ b/problems/472.concatenated-words.md @@ -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) diff --git a/thinkings/trie.md b/thinkings/trie.md new file mode 100644 index 000000000..d3e0bd50b --- /dev/null +++ b/thinkings/trie.md @@ -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)