642. Design Search Autocomplete System
Hard
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:
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
Operation: input(' ')
Output: ["i love you","i love leetcode"]
Explanation:
There are only two sentences that have prefix
Operation: input('a')
Output: []
Explanation:
There are no sentences that have prefix
Operation: input('#')
Output: []
Explanation:
The user finished the input, the sentence
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
timesNow, 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | typedef pair<int, string> MYPAIR; class TrieNode{ public: bool isEnd; int times; vector<TrieNode*> children; TrieNode():isEnd(false), times(0){children.resize(256);} }; class AutocompleteSystem { struct comp{ bool operator()(MYPAIR& p1, MYPAIR& p2){ if(p1.first==p2.first) return p1.second<p2.second; else return p1.first>p2.first; } }; TrieNode* root; TrieNode* ptr;//current position for input string curstr;//current string for input void insert(string s, int t = -1){ TrieNode* p = root; for(auto c:s){ if(p->children[c]==NULL){ p->children[c] = new TrieNode(); } p = p->children[c]; } p->isEnd = true; p->times += t<0?1:t; } void search(priority_queue<MYPAIR, vector<MYPAIR>, comp> &pq, TrieNode *p, string str){ if(p->isEnd){ pq.push(make_pair(p->times, str)); if(pq.size()>3) pq.pop(); } for(int i=0; i<256; ++i){ if(p->children[i]!=NULL) search(pq, p->children[i], str+char(i)); } } public: AutocompleteSystem(vector<string>& sentences, vector<int>& times) { root = new TrieNode(); for(int i=0; i<sentences.size(); ++i){ insert(sentences[i], times[i]); } ptr = root; curstr = ""; } vector<string> input(char c) { vector<string> ret; if(c=='#'){ insert(curstr); curstr = ""; ptr = root; }else if(ptr==NULL || ptr->children[c]==NULL){ ptr->children[c] = new TrieNode(); ptr = ptr->children[c]; curstr += c; }else{ priority_queue<MYPAIR, vector<MYPAIR>, comp> pq; ptr = ptr->children[c]; curstr += c; search(pq, ptr, curstr); ret.insert(ret.begin(), pq.top().second); pq.pop(); } } return ret; } }; /** * Your AutocompleteSystem object will be instantiated and called as such: * AutocompleteSystem* obj = new AutocompleteSystem(sentences, times); * vector<string> param_1 = obj->input(c); */ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | class AutocompleteSystem { class TrieNode{ boolean isEnd; TrieNode[] children; int hot; TrieNode(){ isEnd = false; children = new TrieNode[256]; hot = 0; } } TrieNode root; TrieNode ptr; String cur = ""; public AutocompleteSystem(String[] sentences, int[] times) { root = new TrieNode(); ptr = root; int n = sentences.length; for(int i=0; i<n; ++i){ build(sentences[i], times[i]); } } void build(String str, int time){ TrieNode p = root; for(char c : str.toCharArray()){ int i = (int)c; if(p.children[i]==null){ p.children[i] = new TrieNode(); } p = p.children[i]; } p.isEnd = true; p.hot += time; } void search(TrieNode p, String s, PriorityQueue<Map.Entry<String, Integer>> pq){ if(p.isEnd){ pq.add(Map.entry(s, p.hot)); if(pq.size()>3) pq.poll(); } for(int i=0; i<256; ++i){ if(p.children[i]!=null){ search(p.children[i], s+(char)i, pq); } } } public List<String> input(char c) { if(c!='#' && ptr.children[(int)c]!=null){ PriorityQueue<Map.Entry<String, Integer>> pq = new PriorityQueue<>((a, b)->{ if(a.getValue()==b.getValue()) return b.getKey().compareTo(a.getKey()); else return a.getValue()-b.getValue(); }); search(ptr.children[(int)c], cur+c, pq); List<String> list = new ArrayList<>(); while(!pq.isEmpty()){ list.add(0, pq.poll().getKey()); } cur += c; ptr = ptr.children[(int)c]; return list; }else if(c=='#'){ build(cur, 1); cur = ""; ptr = root; }else{//is null ptr.children[(int)c] = new TrieNode(); ptr = ptr.children[(int)c]; cur += c; } return new ArrayList<>(); } } |
No comments:
Post a Comment