642. Design Search Autocomplete System
by Botao Xiao
642. Design Search Autocomplete System
Question
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
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.
Solutions:
- Method 1: Trie Tree + Priority Queue
class AutocompleteSystem { private static class Node{ Map<Character, Node> childs; Map<String, Integer> freq; boolean isLeaf; public Node(){ this.childs = new HashMap<>(); this.freq = new HashMap<>(); } } private static class Pair{ String s; int count; public Pair(String s, int count){ this.s = s; this.count = count; } } private Node root; private String search; private void add(String s, int count){ char[] arr = s.toCharArray(); Node temp = root; for(int i = 0; i < arr.length; i++){ if(!temp.childs.containsKey(arr[i])){ temp.childs.put(arr[i], new Node()); } temp = temp.childs.get(arr[i]); temp.freq.put(s, temp.freq.getOrDefault(s, 0) + count); } temp.isLeaf = true; } public AutocompleteSystem(String[] sentences, int[] times) { this.root = new Node(); this.search = ""; for(int i = 0; i < times.length; i++){ add(sentences[i], times[i]); } } public List<String> input(char c) { if(c == '#'){ add(search, 1); search = ""; return new ArrayList<>(); } search += c; Node temp = root; for(char cc : search.toCharArray()){ if(!temp.childs.containsKey(cc)){ return new ArrayList<>(); } temp = temp.childs.get(cc); } PriorityQueue<Pair> pq = new PriorityQueue<>(new Comparator<Pair>(){ @Override public int compare(Pair p1, Pair p2){ return p1.count == p2.count ? p1.s.compareTo(p2.s) : p2.count - p1.count; } }); for(Map.Entry<String, Integer> entry : temp.freq.entrySet()){ pq.offer(new Pair(entry.getKey(), entry.getValue())); } List<String> res = new ArrayList<>(); for(int i = 0; i < 3 && !pq.isEmpty(); i++){ res.add(pq.poll().s); } return res; } } /** * Your AutocompleteSystem object will be instantiated and called as such: * AutocompleteSystem obj = new AutocompleteSystem(sentences, times); * List<String> param_1 = obj.input(c); */
Subscribe via RSS