英文原文
In English, we have a concept called root, which can be followed by some other word to form another longer word - let's call this word successor. For example, when the root "an" is followed by the successor word "other", we can form a new word "another".
Given a dictionary consisting of many roots and a sentence consisting of words separated by spaces, replace all the successors in the sentence with the root forming it. If a successor can be replaced by more than one root, replace it with the root that has the shortest length.
Return the sentence after the replacement.
Example 1:
Input: dictionary = ["cat","bat","rat"], sentence = "the cattle was rattled by the battery" Output: "the cat was rat by the bat"
Example 2:
Input: dictionary = ["a","b","c"], sentence = "aadsfasf absbs bbab cadsfafs" Output: "a a b c"
Example 3:
Input: dictionary = ["a", "aa", "aaa", "aaaa"], sentence = "a aa a aaaa aaa aaa aaa aaaaaa bbb baba ababa" Output: "a a a a a a a a bbb baba a"
Example 4:
Input: dictionary = ["catt","cat","bat","rat"], sentence = "the cattle was rattled by the battery" Output: "the cat was rat by the bat"
Example 5:
Input: dictionary = ["ac","ab"], sentence = "it is abnormal that this solution is accepted" Output: "it is ab that this solution is ac"
Constraints:
1 <= dictionary.length <= 10001 <= dictionary[i].length <= 100dictionary[i]consists of only lower-case letters.1 <= sentence.length <= 10^6sentenceconsists of only lower-case letters and spaces.- The number of words in
sentenceis in the range[1, 1000] - The length of each word in
sentenceis in the range[1, 1000] - Each two consecutive words in
sentencewill be separated by exactly one space. sentencedoes not have leading or trailing spaces.
中文题目
在英语中,我们有一个叫做 词根(root)的概念,它可以跟着其他一些词组成另一个较长的单词——我们称这个词为 继承词(successor)。例如,词根an,跟随着单词 other(其他),可以形成新的单词 another(另一个)。
现在,给定一个由许多词根组成的词典和一个句子。你需要将句子中的所有继承词用词根替换掉。如果继承词有许多可以形成它的词根,则用最短的词根替换它。
你需要输出替换之后的句子。
示例 1:
输入:dictionary = ["cat","bat","rat"], sentence = "the cattle was rattled by the battery" 输出:"the cat was rat by the bat"
示例 2:
输入:dictionary = ["a","b","c"], sentence = "aadsfasf absbs bbab cadsfafs" 输出:"a a b c"
示例 3:
输入:dictionary = ["a", "aa", "aaa", "aaaa"], sentence = "a aa a aaaa aaa aaa aaa aaaaaa bbb baba ababa" 输出:"a a a a a a a a bbb baba a"
示例 4:
输入:dictionary = ["catt","cat","bat","rat"], sentence = "the cattle was rattled by the battery" 输出:"the cat was rat by the bat"
示例 5:
输入:dictionary = ["ac","ab"], sentence = "it is abnormal that this solution is accepted" 输出:"it is ab that this solution is ac"
提示:
1 <= dictionary.length <= 10001 <= dictionary[i].length <= 100dictionary[i]仅由小写字母组成。1 <= sentence.length <= 10^6sentence仅由小写字母和空格组成。sentence中单词的总量在范围[1, 1000]内。sentence中每个单词的长度在范围[1, 1000]内。sentence中单词之间由一个空格隔开。sentence没有前导或尾随空格。
通过代码
官方题解
方法一:前缀哈希【通过】
思路
遍历句子中每个单词,查看单词前缀是否为词根。
算法
将所有词根 roots 存储到集合 Set 中。遍历所有单词,判断其前缀是否为词根。如果是,则使用前缀代替该单词;否则不改变该单词。
[solution1-Python]def replaceWords(self, roots, sentence): rootset = set(roots) def replace(word): for i in xrange(1, len(word)): if word[:i] in rootset: return word[:i] return word return " ".join(map(replace, sentence.split()))
[solution1-Java]class Solution { public String replaceWords(List<String> roots, String sentence) { Set<String> rootset = new HashSet(); for (String root: roots) rootset.add(root); StringBuilder ans = new StringBuilder(); for (String word: sentence.split("\\s+")) { String prefix = ""; for (int i = 1; i <= word.length(); ++i) { prefix = word.substring(0, i); if (rootset.contains(prefix)) break; } if (ans.length() > 0) ans.append(" "); ans.append(prefix); } return ans.toString(); } }
复杂度分析
时间复杂度:$O(\sum w_i^2)$,其中 $w_i$ 是第 $i$ 个单词的长度。检查第 $i$ 个单词的所有前缀花费时间 $O(w_i^2)$。
空间复杂度:$O(N)$,其中 $N$ 是句子的长度,词根使用
rootset存储。
方法二:前缀树【通过】
思路和算法
把所有的词根放入前缀树中,在树上查找每个单词的最短词根,该操作可在线性时间内完成。
[solution2-Python]class Solution(object): def replaceWords(self, roots, sentence): Trie = lambda: collections.defaultdict(Trie) trie = Trie() END = True for root in roots: reduce(dict.__getitem__, root, trie)[END] = root def replace(word): cur = trie for letter in word: if letter not in cur or END in cur: break cur = cur[letter] return cur.get(END, word) return " ".join(map(replace, sentence.split()))
[solution2-Java]class Solution { public String replaceWords(List<String> roots, String sentence) { TrieNode trie = new TrieNode(); for (String root: roots) { TrieNode cur = trie; for (char letter: root.toCharArray()) { if (cur.children[letter - 'a'] == null) cur.children[letter - 'a'] = new TrieNode(); cur = cur.children[letter - 'a']; } cur.word = root; } StringBuilder ans = new StringBuilder(); for (String word: sentence.split("\\s+")) { if (ans.length() > 0) ans.append(" "); TrieNode cur = trie; for (char letter: word.toCharArray()) { if (cur.children[letter - 'a'] == null || cur.word != null) break; cur = cur.children[letter - 'a']; } ans.append(cur.word != null ? cur.word : word); } return ans.toString(); } } class TrieNode { TrieNode[] children; String word; TrieNode() { children = new TrieNode[26]; } }
复杂度分析
时间复杂度:$O(N)$,其中 $N$ 是
sentence的长度。每次查询操作为线性时间复杂度。空间复杂度:$O(N)$,前缀树的大小。
统计信息
| 通过次数 | 提交次数 | AC比率 |
|---|---|---|
| 22811 | 38772 | 58.8% |
提交历史
| 提交时间 | 提交结果 | 执行时间 | 内存消耗 | 语言 |
|---|
相似题目
| 题目 | 难度 |
|---|---|
| 实现 Trie (前缀树) | 中等 |