648. Replace Words**
https://leetcode.com/problems/replace-words/
题目描述
In English, we have a concept called root
, which can be followed by some other words to form another longer word - let’s call this word successor
. For example, the root an
, followed by other
, which can form another word another
.
Now, given a dictionary consisting of many roots and a sentence. You need to replace all the successor
in the sentence with the root
forming it. If a successor
has many roots
can form it, replace it with the root
with the shortest length.
You need to output the sentence after the replacement.
Example 1:
Input: dict = ["cat", "bat", "rat"]
sentence = "the cattle was rattled by the battery"
Output: "the cat was rat by the bat"
Note:
- The input will only have lower-case letters.
1 <= dict words number <= 1000
1 <= sentence words number <= 1000
1 <= root length <= 100
1 <= sentence words length <= 1000
C++ 实现 1
思路: 这道题要使用 Trie 树才能获得 O(n) 的结果. 这里先使用哈希表求解.
使用 unordered_map
, 不仅存储 root, 还把 root 的大小给存储. 这样方便后面访问 substr.
那么对于 record 中的每个 root, 判断 sentence 中的每个 word 的同样长度的 substr 是否刚好等于 root, 如果是的话, 那么就替换 word 为 root.
class Solution {
public:
string replaceWords(vector<string>& dict, string sentence) {
unordered_map<string, int> record;
for (auto &word : dict)
record[word] = word.size();
stringstream ss(sentence);
string str;
string res = "";
while (ss >> str) {
int n = str.size();
string rep = str;
for (auto &iter : record) {
if (iter.second <= n &&
iter.first == str.substr(0, iter.second) &&
iter.first.size() < rep.size()) { // 第三个判断保证 prefix 长度最小.
rep = iter.first;
}
}
res += " " + rep;
}
int sz = res.size();
return res.substr(1, sz - 1);
}
};
C++ 实现 2
leetcode 的解法: https://leetcode.com/articles/replace-words/. 在哈希表中存储所有的 root, 当访问 sentence 中每一个 word 时, 判断 word 的 prefix 是否存在, 如果存在的话, 就用这个 prefix 来替换 word.
class Solution {
public:
string replaceWords(vector<string>& dict, string sentence) {
unordered_set<string> record(dict.begin(), dict.end());
stringstream ss(sentence);
string word;
string res = "";
while (ss >> word) {
string prefix = "";
// 访问 word 中每一个字符, 判断 prefix 是否已经在 record 中,
// 这样可以保证即使 prefix 有多个, 但能得到最小的 prefix.
for (int i = 1; i <= word.size(); ++i) {
prefix = word.substr(0, i);
if (record.count(prefix))
break;
}
// 在每个单词后面添加空格.
if (res.size() > 0) res += " ";
res += prefix;
}
return res;
}
};
C++ 实现 3
使用 Trie 树来解决. 参考两个:
- leetcode 的解法: https://leetcode.com/articles/replace-words/, 用的 Java, 好理解;
- C++ trietree solution easy to read and understand, 了解下 C++ 的实现.
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];
}
}
再来看 C++ 的版本:
C++ trietree solution easy to read and understand
The idea is very simple. Use the vector of string to build a trie tree. When there is a shorter root word then we stop build. For sentence, we check the tree and find is there any word to replace. For node, we record its corresponding string.
class Solution {
public:
string replaceWords(vector<string>& dict, string sentence) {
stringstream sen(sentence);
string res="";
string token;
TrieTree tree;
tree.buildTree(dict);
while(getline(sen,token,' ')){
res+=tree.replace(token);
res+=" ";
}
return res.substr(0,res.size()-1); //ignore last space
}
class TrieNode{
public:
bool end;
string str;
TrieNode* children[26];
TrieNode(bool flag, string s){
end=flag;
str=s;
memset(children, 0, sizeof(children));;
}
};
class TrieTree{
public:
TrieNode* root;
TrieTree(){
root= new TrieNode(false,"");
}
void buildTree(vector<string>& dict){
for(string s:dict){
TrieNode* cur =root;
for(char c:s){
if(cur->children[c-'a'] == NULL){
cur->children[c-'a'] = new TrieNode(false,"");
cur = cur->children[c-'a'];
}
else if(cur->children[c-'a']->end==true){ //if a shorter root exists, we just stop build
cur=NULL;
break;
}
else cur=cur->children[c-'a'];
}
if(cur!=NULL){ //mark the string and flag
cur->end=true;
cur->str=s;
}
}
return ;
}
string replace(string s){
TrieNode* cur =root;
string res="";
for(char c:s){
cur=cur->children[c-'a'];
if(cur==NULL) break;
if(cur->end==true){
res=cur->str;
break;
}
}
if(res!="") return res;
return s;
}
};
};