大家好,在leetcode的問題中有一個主題被稱為Design。這類型的問題比較像是要模擬實作出某些系統中的核心功能。今天要來分享和上一個主題Trie有關的Design問題。
題目敘述:
設計一個擁有使用者在輸入關鍵字時會自動提示功能的搜尋引擎。
Example1:
Input
["AutocompleteSystem", "input", "input", "input", "input"]
[[["i love you", "island", "iroman", "i love leetcode"], [5, 3, 2, 2]], ["i"], [" "], ["a"], ["#"]]
Output
[null, ["i love you", "island", "i love leetcode"], ["i love you", "i love leetcode"], [], []]
解釋:
使用者輸入"i"後,程式判斷出"i love you"符合並且有5次搜尋紀錄,所以排最前面;"island"有3次排第二;"iroman"和"i love leetcode"都出現過兩次,所以要比較"i"後面的字元的ASCII-code:"r"和" ",因為空格的ASCII-code比較小,所以排在第三個的是"i love leetcode"。
分析:
class TrieNode:
def __init__(self):
self.finished = False
self.content = ""
self.children = {}
class Trie:
def __init__(self):
self.root = TrieNode()
self.sentenceCount = {}
def add(self, sentence, time):
self.sentenceCount[sentence] = time
curr = self.root
for s in sentence:
if s not in curr.children:
curr.children[s] = TrieNode()
curr = curr.children[s]
curr.finished = True
curr.content = sentence
def startWith(self, prefix):
curr = self.root
for c in prefix:
if c not in curr.children:
return None
curr = curr.children[c]
return curr
class AutocompleteSystem:
def __init__(self, sentences: List[str], times: List[int]):
self.sys = Trie()
for sentence, time in zip(sentences, times):
self.sys.add(sentence, time)
self.prefix = ""
def input(self, c: str) -> List[str]:
if c == '#':
if self.prefix in self.sys.sentenceCount:
self.sys.sentenceCount[self.prefix] += 1
else:
self.sys.add(self.prefix, 1)
self.prefix = ""
return []
self.prefix += c
node = self.sys.startWith(self.prefix)
if not node:
return []
h = []
res = deque()
def dfs(root):
if root.finished:
heapq.heappush(h, (-1 * self.sys.sentenceCount[root.content],root.content))
if len(root.children) == 0:
return
for c in root.children:
dfs(root.children[c])
dfs(node)
prev, order = None, defaultdict(list)
while h:
num, sentence = heapq.heappop(h)
if res and prev == num:
self.compete(num, sentence, order)
for i, (_, hot) in enumerate(res):
if hot == -num:
for j in range(len(order[num])):
if i + j < len(res):
res[i + j] = (order[num][j], -num)
elif len(res) < 3:
res.append((order[num][j], -num))
break
elif not res or (len(res) < 3 and prev != num):
res.append((sentence, -num))
prev = num
order[num].append(sentence)
# print(self.sys.sentenceCount)
return [s for s, _ in res]
def compete(self, num, sentence, order):
order[num].append(sentence)
order[num].sort(key = lambda x: [ord(c) for c in x])
# Your AutocompleteSystem object will be instantiated and called as such:
# obj = AutocompleteSystem(sentences, times)
# param_1 = obj.input(c)
這個解法只是當下看到這個問題時最直覺的反應,然後就寫了將近百行的程式(我在leetcode中寫過最長的),目前還沒有參考其他人的解答,相信一定有更好的解法。
對了,本題僅對有leetcode premium的使用者開放,所以沒有premium的人無法在leetcode作答這題😅。