1268. Search Suggestions System - cocoder39/coco39_LC GitHub Wiki
1268. Search Suggestions System
Option 1: 直觉用trie + search (hashmap or dfs)
Given M products and avg length of each product is N
- time complexity
- sort O(M * log(M)) (string comparison is simplified to O(1))
- build trie time complexity is O(M * N) where M*N is total number of trie nodes
- search O(N) to traverse the prefix in trie
- space complexity
- O(M * N) trine nodes
- worst case each trie node contains all the M words
1.1 trie + hash
class TrieNode:
def __init__(self):
self.children = collections.defaultdict(TrieNode)
self.words = []
class Solution:
def suggestedProducts(self, products: List[str], searchWord: str) -> List[List[str]]:
products.sort() # so words are appended to cur.words in order
root = self.buildTrie(products)
return self.search(root, searchWord)
def buildTrie(self, products: List[str]) -> 'TrieNode':
root = TrieNode()
for product in products:
cur = root
for ch in product:
cur = cur.children[ch]
cur.words.append(product)
if len(cur.words) > 3:
cur.words.pop()
return root
def search(self, root: TrieNode, searchWord: str) -> List[List[str]]:
res = []
cur = root
for i, ch in enumerate(searchWord):
if ch in cur.children:
cur = cur.children[ch]
res.append(cur.words)
else:
for j in range(i, len(searchWord)):
res.append([])
break
return res
1.2 Trie + dfs
Given M products and avg length of each product is N
- time complexity
- build trie time complexity is O(M * N) where M*N is total number of trie nodes
- search
- for loop N * (trie traversal O(N) + dfs O(26 * N * 3)) -> O(N^2)
- space complexity O(M * N) for building trie
class TrieNode:
def __init__(self):
self.children = collections.defaultdict(TrieNode)
self.word = None
self.isWord = False
class Solution:
def suggestedProducts(self, products: List[str], searchWord: str) -> List[List[str]]:
root = self.buildTrie(products)
res = []
prefix = ''
for ch in searchWord:
prefix += ch
res.append(self.search(root, prefix))
return res
def buildTrie(self, products: List[str]) -> 'TrieNode':
root = TrieNode()
for product in products:
cur = root
for ch in product:
cur = cur.children[ch]
cur.isWord = True
cur.word = product
return root
def search(self, root: TrieNode, prefix: str) -> List[str]:
cur = root
for ch in prefix:
if ch in cur.children:
cur = cur.children[ch]
else:
return []
res = []
self.dfs(cur, res)
return res
def dfs(self, root: TrieNode, res: List[str]) -> None:
if not root or len(res) == 3:
return
if root.isWord:
res.append(root.word)
cur = root
for i in range(ord('a'), ord('z') + 1):
ch = chr(i)
if ch in cur.children:
self.dfs(cur.children[ch], res)
Option 2: binary search (最优)
Given M products and avg length of each product is N
- time complexity
- sort O(MN * log M) instead of O(M * log M) because string comparison is O(N) instead of O(1)
- external for loop N + binary search O(N * log M) instead of O(log M) because string comparison is O(N)
- O((M+N) * N * log M)
- space complexity
- O(n) since python sort is build on a variant of merge sort
class Solution:
def suggestedProducts(self, products: List[str], searchWord: str) -> List[List[str]]:
products.sort()
res, prefix = [], ''
for ch in searchWord:
res.append([])
prefix += ch
i = bisect.bisect_left(products, prefix)
for word in products[i:i + 3]:
if word.startswith(prefix):
res[-1].append(word)
return res