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,我们的做法是:
我们构造的前缀树大概是这样的:
问题的关键在于第二步中的查找每一个单词有几个单词表中的单词组成。 其实如果你了解前缀树的话应该不难写出来。 比如查找 catsdogcats:
很明显这个逻辑是错误的,正确的划分应该是:
由于我们并不知道 cat 这里断开,结果更大?还是 cats 这里断开结果更大?因此我们的做法是将其全部递归求出,然后取出最大值即可。如果我们直接这样递归的话,可能会超时,卡在最后一个测试用例上。一个简单的方式是记忆化递归,从而避免重复计算,经测试这种方法能够通过。
2021-12-28 updated: 由于力扣增加了测试用例,导致了上面的仅仅依靠记忆化也是无法 AC 的。需要进一步优化。
我们可以将 words 排序,这样就可以剪枝了。如何剪枝呢?直接用代码比较直观:
for word in words:
if trie.cntWords(word) >= 2:
res.append(word)
else:
trie.insert(word)
如果如果 word 是合成词,那么没有必要将其加到 trie 中,因为这不影响答案,最多就是 cntWords 算出来的数字不对了。不过这道题对具体的数字不感兴趣,我们只关心是否大于 2。
需要注意的是, 一定要排序。 否则如果合成词在前就没有优化效果了,达不到剪枝的目的。
代码支持:Python3
Python3 Code:
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]:
trie = Trie()
res = []
words.sort(key=len)
for word in words:
if trie.cntWords(word) >= 2:
res.append(word)
else:
trie.insert(word)
return res
大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 37K star 啦。
大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。