题目:
Design a search autocomplete system for a search engine. Users may input a sentence (at least one word and end with a special character '#'
). For each character they type except '#', you need to return the top 3 historical hot sentences that have prefix the same as the part of sentence already typed. Here are the specific rules:
- The hot degree for a sentence is defined as the number of times a user typed the exactly same sentence before.
- The returned top 3 hot sentences should be sorted by hot degree (The first is the hottest one). If several sentences have the same degree of hot, you need to use ASCII-code order (smaller one appears first).
- If less than 3 hot sentences exist, then just return as many as you can.
- When the input is a special character, it means the sentence ends, and in this case, you need to return an empty list.
Your job is to implement the following functions:
The constructor function:
AutocompleteSystem(String[] sentences, int[] times):
This is the constructor. The input is historical data. Sentences
is a string array consists of previously typed sentences. Times
is the corresponding times a sentence has been typed. Your system should record these historical data.
Now, the user wants to input a new sentence. The following function will provide the next character the user types:
List<String> input(char c):
The input c
is the next character typed by the user. The character will only be lower-case letters ('a'
to 'z'
), blank space (' '
) or a special character ('#'
). Also, the previously typed sentence should be recorded in your system. The output will be the top 3 historical hot sentences that have prefix the same as the part of sentence already typed.
Example:
Operation: AutocompleteSystem(["i love you", "island","ironman", "i love leetcode"], [5,3,2,2])
The system have already tracked down the following sentences and their corresponding times:
"i love you"
: 5
times
"island"
: 3
times
"ironman"
: 2
times
"i love leetcode"
: 2
times
Now, the user begins another search:
Operation: input('i')
Output: ["i love you", "island","i love leetcode"]
Explanation:
There are four sentences that have prefix "i"
. Among them, "ironman" and "i love leetcode" have same hot degree. Since ' '
has ASCII code 32 and 'r'
has ASCII code 114, "i love leetcode" should be in front of "ironman". Also we only need to output top 3 hot sentences, so "ironman" will be ignored.
Operation: input(' ')
Output: ["i love you","i love leetcode"]
Explanation:
There are only two sentences that have prefix "i "
.
Operation: input('a')
Output: []
Explanation:
There are no sentences that have prefix "i a"
.
Operation: input('#')
Output: []
Explanation:
The user finished the input, the sentence "i a"
should be saved as a historical sentence in system. And the following input will be counted as a new search.
Note:
- The input sentence will always start with a letter and end with '#', and only one blank space will exist between two words.
- The number of complete sentences that to be searched won't exceed 100. The length of each sentence including those in the historical data won't exceed 100.
- Please use double-quote instead of single-quote when you write test cases even for a character input.
- Please remember to RESET your class variables declared in class AutocompleteSystem, as static/class variables are persisted across multiple test cases. Please see here for more details.
思路:
一道字典树的应用题目。我们在定义字典树节点的时候,给里面包含一个count项,如果count == 0则表示该节点不是尾节点;否则就表示该对应的字符串出现的次数(一定是大于0的)。在构造函数中,我们将每个sentence都加入到字典树中。在input函数中,我们每得到一个字符,就将截止目前所构成的前缀加入到字典树中,并且用DFS方法获得所有包含该前缀的字符串。最后返回热度最高的三个字符串即可。
代码:
class AutocompleteSystem {
public:
AutocompleteSystem(vector<string> sentences, vector<int> times) {
root = new Trie();
node = root;
search_input.clear();
for (int i = 0; i < sentences.size(); ++i) {
addNode(sentences[i], times[i]);
}
}
vector<string> input(char c) {
if (c == '#') {
addNode(search_input, 1);
search_input = "";
node = root;
return {};
}
else {
search_input += c;
int index = c == ' ' ? 0 : 1 + c - 'a';
if (node->children[index] == NULL) {
node->children[index] = new Trie();
}
node = node->children[index];
vector<pair<int, string>> search_results;
DFS(node, search_input, search_results);
sort(search_results.begin(), search_results.end());
vector<string> ret;
for (int i = 0; i < min(3, (int)search_results.size()); ++i) {
ret.push_back(search_results[i].second);
}
return ret;
}
}
private:
struct Trie {
int count; // 0 means not the end point, otherwise mean the count
vector<Trie*> children;
Trie() {
count = 0;
children = vector<Trie*>(27, NULL);
}
};
void addNode(string &s, int time) {
Trie *node = root;
for (int i = 0; i < s.length(); ++i) {
int index = s[i] == ' ' ? 0 : s[i] - 'a' + 1;
if (node->children[index] == NULL) {
node->children[index] = new Trie();
}
node = node->children[index];
}
node->count += time;
}
void DFS(Trie *node, string prefix, vector<pair<int, string>> &results) {
if (node == NULL) {
return;
}
if (node->count > 0) {
results.push_back(make_pair(-node->count, prefix)); // make larger values in front after sort
}
for (int i = 0; i < 27; ++i) {
char c = i == 0 ? ' ' : 'a' + i - 1;
DFS(node->children[i], prefix + c, results);
}
}
Trie *root, *node;
string search_input;
};
/**
* Your AutocompleteSystem object will be instantiated and called as such:
* AutocompleteSystem obj = new AutocompleteSystem(sentences, times);
* vector<string> param_1 = obj.input(c);
*/