在英语中,我们有一个叫做 词根(root) 的概念,可以词根 后面 添加其他一些词组成另一个较长的单词------我们称这个词为 衍生词 (derivative)。例如,词根 help,跟随着 继承词 "ful",可以形成新的单词 "helpful"。
现在,给定一个由许多 词根 组成的词典 dictionary 和一个用空格分隔单词形成的句子 sentence。你需要将句子中的所有 衍生词 用 词根 替换掉。如果 衍生词 有许多可以形成它的 词根,则用 最短 的 词根 替换它。
你需要输出替换之后的句子。
示例 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"
提示:
1 <= dictionary.length <= 1000
1 <= dictionaryi.length <= 100
dictionaryi 仅由小写字母组成。
1 <= sentence.length <= 106^66
sentence 仅由小写字母和空格组成。
sentence 中单词的总量在范围 1, 1000 内。
sentence 中每个单词的长度在范围 1, 1000 内。
sentence 中单词之间由一个空格隔开。
sentence 没有前导或尾随空格。
我们可以使用字典树,先把所有词根前缀存入字典树,然后对sentence中的每个单词查询是否在字典树中,如果在,就只保留前缀:
cpp
class Node {
public:
vector<Node *> next = vector<Node *>(26, nullptr);
bool isEnd = false;
};
class Solution {
public:
string replaceWords(vector<string>& dictionary, string sentence) {
Node *root = new Node();
// 存入字典树
for (string s : dictionary) {
Node *curNode = root;
for (char c : s) {
if (curNode->next[c - 'a'] == nullptr) {
curNode->next[c - 'a'] = new Node();
}
curNode = curNode->next[c - 'a'];
}
curNode->isEnd = true;
}
string ans;
for (int i = 0; i < sentence.size(); ++i) {
Node *curNode = root;
while (i < sentence.size() && sentence[i] != ' ') {
char c = sentence[i];
// 逐字符字典树查找
if (curNode->next[c - 'a'] != nullptr) {
ans += c;
curNode = curNode->next[c - 'a'];
// 如果是一个前缀
if (curNode->isEnd) {
break;
}
} else {
break;
}
++i;
}
while (i < sentence.size() && sentence[i] != ' ') {
// 如果没找到词根前缀,就把单词完整放入答案
if (!curNode->isEnd) {
ans += sentence[i];
}
++i;
}
if (i < sentence.size() && sentence[i] == ' ') {
ans += ' ';
}
}
return ans;
}
};
如果词缀中有n个字母,sentence的长度为m,则此算法时间复杂度为O(n+m),空间复杂度为O(n)。