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:
- 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.
-
设计一个搜索自动补全系统。
Python:
# Time: O(p^2), p is the length of the prefix
# Space: O(p * t + s), t is the number of nodes of trie
# , s is the size of the sentences
import collections
class TrieNode(object):
def __init__(self):
self.__TOP_COUNT = 3
self.infos = []
self.leaves = {}
def insert(self, s, times):
cur = self
cur.add_info(s, times)
for c in s:
if c not in cur.leaves:
cur.leaves[c] = TrieNode()
cur = cur.leaves[c]
cur.add_info(s, times)
def add_info(self, s, times):
for p in self.infos:
if p[1] == s:
p[0] = -times
break
else:
self.infos.append([-times, s])
self.infos.sort()
if len(self.infos) > self.__TOP_COUNT:
self.infos.pop()
class AutocompleteSystem(object):
def __init__(self, sentences, times):
"""
:type sentences: List[str]
:type times: List[int]
"""
self.__trie = TrieNode()
self.__cur_node = self.__trie
self.__search = []
self.__sentence_to_count = collections.defaultdict(int)
for sentence, count in zip(sentences, times):
self.__sentence_to_count[sentence] = count
self.__trie.insert(sentence, count)
def input(self, c):
"""
:type c: str
:rtype: List[str]
"""
result = []
if c == '#':
self.__sentence_to_count["".join(self.__search)] += 1
self.__trie.insert("".join(self.__search), self.__sentence_to_count["".join(self.__search)])
self.__cur_node = self.__trie
self.__search = []
else:
self.__search.append(c)
if self.__cur_node:
if c not in self.__cur_node.leaves:
self.__cur_node = None
return []
self.__cur_node = self.__cur_node.leaves[c]
result = [p[1] for p in self.__cur_node.infos]
return result
# Your AutocompleteSystem object will be instantiated and called as such:
# obj = AutocompleteSystem(sentences, times)
# param_1 = obj.input(c)