题目来源
题目描述
题目解析
这道题给了我们一个前缀字典,又给了一个句子,让我们将句子中较长的单次替换成其前缀(如果在前缀字典中存在的话)。
关键点:如果查找word1是不是word2的前缀
前缀哈希
需要解决的问题:
- 切割sentence,得到每一个word:
- 由于C++中没有split函数,所以可以采用字符串流来提取每一个单词
- 对于每一个word,去dict中寻找最短前缀。
- 预处理:
- 优化:对于每一个单词,可以根据第一个字母来快速定位。比如cattle这个单词的的首字母是c,那么我们在前缀字典中找所有开头是
c
的前缀,为了方便查找,我们将首字母相同的前缀都放在同一个数组中,总共需要26个数组,所以我们可以定义一个二维数组来装这些前缀 - 怎么确保最短呢?可以先按照单词的长度来给所有的前缀排序,然后再一次加入对应的数组中,这样就可以保证短的前缀在前面
- 优化:对于每一个单词,可以根据第一个字母来快速定位。比如cattle这个单词的的首字母是c,那么我们在前缀字典中找所有开头是
- 怎么判断是不是前缀呢?
- 对于每一个遍历到的word,我们根据首字母来查找数组中所有以该首字母开始的前缀,然后直接用substr函数来提取单词中和前缀长度相同的子字符串来跟前缀比较,如果二者相等说明可以用前缀来替换单词,然后break掉for循环。别忘了单词之前还要加上空格
- 预处理:
class Solution {
public:
string replaceWords(vector<string>& dictionary, string sentence) {
std::vector<std::vector<std::string>> vec(26);
sort(dictionary.begin(), dictionary.end(), [](const string&a, const string& b){
return a.size() < b.size();
});
for(std::string dict : dictionary){
vec[dict[0] - 'a'].emplace_back(dict);
}
std::string t, ans;
std::istringstream ss(sentence);
while (ss >> t){
for(std::string &word : vec[t[0] - 'a']){
if(t.substr(0, word.size()) == word){
t = word;
break;
}
}
ans += t + " ";
}
ans.pop_back();
return ans;
}
};
前缀树
更好的方法是使用前缀树。
- 先遍历dictionary,将dictionary中的单词放到前缀树中
- 然后切割sentence,得到一个个word,然后去前缀树中查询有没有对应的前缀存在,如果有就返回这个前缀,否则原样返回
class Solution {
struct TrieNode{
bool isWord;
std::vector<TrieNode*> children;
TrieNode()
: isWord(false)
, children(26, nullptr)
{
}
~TrieNode(){
for(auto it : children){
delete it;
}
}
};
void buildTree(TrieNode* root, vector<string>& dictionary) {
TrieNode *curr;
for (string &word : dictionary){
curr = root;
for(auto ch : word){
if(curr->children[ch - 'a'] == nullptr){
curr->children[ch - 'a'] = new TrieNode();
}
curr = curr->children[ch - 'a'];
}
curr->isWord = true;
}
}
std::string findPrefix(TrieNode* root , const std::string &word){
auto curr = root;
std::string ans;
for(auto ch : word){
if(curr->isWord || curr->children[ch - 'a'] == nullptr){
break;
}
ans += ch;
curr = curr->children[ch - 'a'];
}
return curr->isWord ? ans : ""; //有前缀返回前缀,没有则返回空字符串
}
public:
string replaceWords(vector<string>& dictionary, string sentence) {
TrieNode* root = new TrieNode();
buildTree(root, dictionary);
std::string t, ans;
std::istringstream ss(sentence);
while (ss >> t){
std::string prefix = findPrefix(root, t);
if(prefix.empty()){
ans += t + " ";
}else{
ans += prefix + " ";
}
}
ans.pop_back();
delete root;
return ans;
}
};