携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情
题目链接:648. 单词替换
题目描述
在英语中,我们有一个叫做 词根 (root) 的概念,可以词根 后面 添加其他一些词组成另一个较长的单词——我们称这个词为 继承词(successor)。例如,词根 an,跟随着单词 other(其他),可以形成新的单词 another(另一个)。
现在,给定一个由许多 词根 组成的词典 dictionary 和一个用空格分隔单词形成的句子 sentence。你需要将句子中的所有 继承词 用 词根 替换掉。如果 继承词 有许多可以形成它的 词根,则用 最短 的词根替换它。
你需要输出替换之后的句子。
提示:
dictionary[i]仅由小写字母组成。sentence仅由小写字母和空格组成。sentence中单词的总量在范围[1, 1000]内。sentence中每个单词的长度在范围[1, 1000]内。sentence中单词之间由一个空格隔开。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"
整理题意
题目给定一个词根字符串数组 dictionary ,里面包含多个字符串表示词根,然后给定一个字符串 sentence 表示句子,句子中由多个单词和空格组成,让我们将句子中的单词用最短的词根代替,这里代替的要求为词根为当前单词的前缀,且要求是最短的词根。
题目规定句子
sentence仅由小写字母和空格组成,单词的总量在范围[1, 1000]内,单词的长度在范围[1, 1000]内,单词之间由一个空格隔开,没有前导或尾随空格。
解题思路分析
首先很容易想到的是暴力解法,遍历句子 sentence 中每一个单词,然后在词根数组 dictionary 中查找最短的前缀进行替换即可。
方法一:哈希表
但是对于每个单词都要遍历一遍词根数组 dictionary 显得比较冗余,我们可以使用哈希表先将所有词根进行存储,然后在遍历句子 sentence 中每一个单词的时候,由短至长 遍历它所有的前缀(可以保证是最短的词根),第一个出现在哈希表集合中的前缀即为最短词根,将这个词根替换原来的单词。最后返回重新拼接的句子。
具体实现
方法一:哈希表
- 遍历词根数组,使用无序
set集合记录每个词根; - 提取句子中的所有单词放入
words; - 遍历
words数组,由短至长遍历每个单词前缀; - 判断是否为词根,进行替换操作;
- 返回重新拼接的句子。
复杂度分析
- 时间复杂度:。其中
d是dictionary的字符数,构建哈希集合消耗 时间。len是sentence的长度,判断单词的前缀子字符串是否位于哈希集合中消耗 时间。 - 空间复杂度:,其中
s是sentence的字符数。构建哈希集合消耗 空间,分割sentence消耗 空间。
代码实现
方法一:哈希表
class Solution {
public:
string replaceWords(vector<string>& dictionary, string sentence) {
//使用无序集合 set
unordered_set<string> mp;
mp.clear();
//将词根放入集合set中
int n = dictionary.size();
for(int i = 0; i < n; i++){
mp.insert(dictionary[i]);
}
//提取句子中的每个单词
vector<string> words;
words.clear();
int m = sentence.length();
string temp = "";
for(int i = 0; i <= m; i++){
if(i == m || sentence[i] == ' '){
if(temp != "") words.push_back(temp);
temp = "";
}
else{
temp += sentence[i];
}
}
string ans = "";
//由短至长遍历每个单词前缀
int k = words.size();
for(int i = 0; i < k; i++){
int len = words[i].length();
temp = "";
for(int j = 0; j < len; j++){
temp += words[i][j];
//判断是否为词根
if(mp.count(temp)){
break;
}
}
words[i] = temp;
if(i != k - 1) ans += temp + ' ';
else ans += temp;
}
return ans;
}
};
总结
- 使用
set集合比map集合更节省空间。 - 创建无序的集合
unordered_set比有序集合set在查找时更快。 - 该题还可以使用 字典树 解法,与哈希集合不同,我们用
dictionary中所有词根构建一棵字典树,并用特殊符号标记结尾。在搜索前缀时,只需在字典树上搜索出一条最短的前缀路径即可。 - 测试结果:
结束语
一个人的成熟,不仅在于经历过多少事,更在于经历过后的沉淀和思考。不要只顾着埋头向前冲,适时停一停,给自己一点反思的时间。从每一次的经历中有所领悟有所得到,你才能在未来的路上走得更远更稳健。新的一天,加油!