英文原文
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 <= 1000
1 <= dictionary[i].length <= 100
dictionary[i]
consists of only lower-case letters.1 <= sentence.length <= 10^6
sentence
consists of only lower-case letters and spaces.- The number of words in
sentence
is in the range[1, 1000]
- The length of each word in
sentence
is in the range[1, 1000]
- Each two consecutive words in
sentence
will be separated by exactly one space. sentence
does 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 <= 1000
1 <= dictionary[i].length <= 100
dictionary[i]
仅由小写字母组成。1 <= sentence.length <= 10^6
sentence
仅由小写字母和空格组成。sentence
中单词的总量在范围[1, 1000]
内。sentence
中每个单词的长度在范围[1, 1000]
内。sentence
中单词之间由一个空格隔开。sentence
没有前导或尾随空格。
通过代码
官方题解
方法一:前缀哈希【通过】
思路
遍历句子中每个单词,查看单词前缀是否为词根。
算法
将所有词根 roots
存储到集合 Set 中。遍历所有单词,判断其前缀是否为词根。如果是,则使用前缀代替该单词;否则不改变该单词。
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()))
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
存储。
方法二:前缀树【通过】
思路和算法
把所有的词根放入前缀树中,在树上查找每个单词的最短词根,该操作可在线性时间内完成。
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()))
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 (前缀树) | 中等 |