Design Search Autocomplete System

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 3historical hot sentences that have prefix the same as the part of sentence already typed. Here are the specific rules:

  1. The hot degree for a sentence is defined as the number of times a user typed the exactly same sentence before.
  2. 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).
  3. If less than 3 hot sentences exist, then just return as many as you can.
  4. 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. 

 1 class AutocompleteSystem {
 2     private final Map<String, Integer> cache = new HashMap<String, Integer>();
 3     private String input = "";
 4 
 5     public AutocompleteSystem(String[] sentences, int[] times) {
 6         for (int i = 0; i < sentences.length; i++) {
 7             cache.put(sentences[i], times[i]);
 8         }
 9     }
10 
11     public List<String> input(char c) {
12         if (c == '#') {
13             Integer count = cache.getOrDefault(input, 0);
14             cache.put(input, ++count);
15             input = "";
16             return Collections.emptyList();
17         }
18 
19         input += c;
20         return cache.entrySet().stream()
21                 .filter(e -> e.getKey().startsWith(input))
22                 .sorted(Map.Entry.<String, Integer>comparingByValue(Comparator.reverseOrder())
23                         .thenComparing(Map.Entry.comparingByKey()))
24                 .limit(3)
25                 .map(Map.Entry::getKey)
26                 .collect(Collectors.toCollection(ArrayList::new));
27     }
28 }

 

 1 class AutocompleteSystem {
 2     class TrieNode {
 3         Map<Character, TrieNode> children;
 4         Map<String, Integer> counts;
 5         boolean isWord;
 6 
 7         public TrieNode() {
 8             children = new HashMap<>();
 9             counts = new HashMap<>();
10             isWord = false;
11         }
12     }
13 
14     TrieNode root;
15     String prefix;
16 
17     public AutocompleteSystem(String[] sentences, int[] times) {
18         root = new TrieNode();
19         prefix = "";
20         for (int i = 0; i < sentences.length; i++) {
21             add(sentences[i], times[i]);
22         }
23     }
24 
25     private void add(String s, int count) {
26         TrieNode cur = root;
27         for (char c : s.toCharArray()) {
28             TrieNode next = cur.children.get(c);
29             if (next == null) {
30                 next = new TrieNode();
31                 cur.children.put(c, next);
32             }
33             cur = next;
34             cur.counts.put(s, cur.counts.getOrDefault(s, 0) + count);
35         }
36         cur.isWord = true;
37     }
38 
39     public List<String> input(char c) {
40         if (c == '#') {
41             add(prefix, 1);
42             prefix = "";
43             return new ArrayList<String>();
44         }
45 
46         prefix = prefix + c;
47         TrieNode cur = root;
48         for (char ch : prefix.toCharArray()) {
49             TrieNode next = cur.children.get(ch);
50             if (next == null) {
51                 return new ArrayList<String>();
52             }
53             cur = next;
54         }
55 
56         PriorityQueue<Map.Entry<String, Integer>> pq = new PriorityQueue<>((a,
57                 b) -> (a.getValue() == b.getValue() ? a.getKey().compareTo(b.getKey()) : b.getValue() - a.getValue()));
58         for (Map.Entry<String, Integer> entry : cur.counts.entrySet()) {
59             pq.add(entry);
60         }
61 
62         List<String> res = new ArrayList<>();
63         for (int i = 0; i < 3 && !pq.isEmpty(); i++) {
64             res.add(pq.poll().getKey());
65         }
66         return res;
67     }
68 }

 

posted @ 2019-07-15 05:34  北叶青藤  阅读(513)  评论(0编辑  收藏  举报