Bird
Raised Fist0
Interview PreptriesmediumAmazonGoogleFacebook

Search Suggestions System (Autocomplete)

Choose your preparation mode4 modes available
</>
IDE
def suggestedProducts(products: List[str], searchWord: str) -> List[List[str]]:public List<List<String>> suggestedProducts(List<String> products, String searchWord)vector<vector<string>> suggestedProducts(vector<string> &products, string searchWord)function suggestedProducts(products, searchWord)
def suggestedProducts(products, searchWord):
    # Write your solution here
    pass
class Solution {
    public List<List<String>> suggestedProducts(List<String> products, String searchWord) {
        // Write your solution here
        return new ArrayList<>();
    }
}
#include <vector>
#include <string>
using namespace std;

vector<vector<string>> suggestedProducts(vector<string> &products, string searchWord) {
    // Write your solution here
    return {};
}
function suggestedProducts(products, searchWord) {
    // Write your solution here
}
Coming soon
0/10
Common Bugs to Avoid
Wrong: [['mouse', 'mousepad'], ['mouse', 'mousepad'], ['mouse', 'mousepad'], ['mouse', 'mousepad'], ['mouse', 'mousepad']]Not sorting products lexicographically before filtering, causing incorrect suggestion order.✅ Sort products array before processing prefixes: products.sort()
Wrong: [[], [], []]Returning empty suggestions prematurely when products exist but prefix filtering is incorrect.✅ Ensure prefix filtering is done correctly for each prefix and suggestions collected accordingly.
Wrong: [['app'], ['app'], ['app']]Not including duplicates or limiting suggestions to fewer than three when more exist.✅ Do not remove duplicates; return up to three suggestions including duplicates.
Wrong: Timeout or no outputBrute force approach checking all products for each prefix causing TLE.✅ Implement trie data structure with precomputed top 3 suggestions per node for efficient queries.
✓
Test Cases
t1_01basic
Input{"products":["mobile","mouse","moneypot","monitor","mousepad"],"searchWord":"mouse"}
Expected[["mobile","moneypot","monitor"],["mobile","moneypot","monitor"],["mouse","mousepad"],["mouse","mousepad"],["mouse","mousepad"]]

After typing 'm', suggestions are the three lex smallest products starting with 'm'. After 'mo', same. After 'mou', only 'mouse' and 'mousepad' match, so they are suggested, and so on.

t1_02basic
Input{"products":["apple","app","apricot","banana","bat","batch"],"searchWord":"bat"}
Expected[["banana","bat","batch"],["bat","batch"],["bat","batch"]]

For prefix 'b', suggestions are the three lex smallest products starting with 'b'. For 'ba', 'bat' and 'batch' match. For 'bat', only 'bat' and 'batch' match, so both are suggested.

t2_01edge
Input{"products":[],"searchWord":"abc"}
Expected[[],[],[]]

Empty products array means no suggestions for any prefix of searchWord.

t2_02edge
Input{"products":["a"],"searchWord":"a"}
Expected[["a"]]

Single product and single character searchWord; suggestion is the product itself.

t2_03edge
Input{"products":["abc","abcd","abcde"],"searchWord":"abcde"}
Expected[["abc","abcd","abcde"],["abc","abcd","abcde"],["abc","abcd","abcde"],["abcd","abcde"],["abcde"]]

Prefixes exactly match products; suggestions shrink as prefix length increases.

t2_04edge
Input{"products":["aaa","aaa","aaa"],"searchWord":"aa"}
Expected[["aaa","aaa","aaa"],["aaa","aaa","aaa"]]

All products identical; suggestions include duplicates as they appear.

t3_01corner
Input{"products":["a","aa","aaa","aaaa"],"searchWord":"aaaa"}
Expected[["a","aa","aaa"],["aa","aaa","aaaa"],["aaa","aaaa"],["aaaa"]]

Tests correct handling of duplicates and overlapping prefixes with multiple similar products.

t3_02corner
Input{"products":["dog","deer","deal"],"searchWord":"cat"}
Expected[[],[],[]]

searchWord characters not present in any product; suggestions empty from first character.

t3_03corner
Input{"products":["apple","apple","apple","app"],"searchWord":"app"}
Expected[["app","apple","apple"],["app","apple","apple"],["app","apple","apple"]]

Products contain duplicates; suggestions include duplicates as they appear in sorted order.

t4_01performance
Input{"products":["aaaaaaaaaab0","aaaaaaaaaab1","aaaaaaaaaab2","aaaaaaaaaab3","aaaaaaaaaab4","aaaaaaaaaab5","aaaaaaaaaab6","aaaaaaaaaab7","aaaaaaaaaab8","aaaaaaaaaab9","aaaaaaaaaab10","aaaaaaaaaab11","aaaaaaaaaab12","aaaaaaaaaab13","aaaaaaaaaab14","aaaaaaaaaab15","aaaaaaaaaab16","aaaaaaaaaab17","aaaaaaaaaab18","aaaaaaaaaab19","aaaaaaaaaab20","aaaaaaaaaab21","aaaaaaaaaab22","aaaaaaaaaab23","aaaaaaaaaab24","aaaaaaaaaab25","aaaaaaaaaab26","aaaaaaaaaab27","aaaaaaaaaab28","aaaaaaaaaab29","aaaaaaaaaab30","aaaaaaaaaab31","aaaaaaaaaab32","aaaaaaaaaab33","aaaaaaaaaab34","aaaaaaaaaab35","aaaaaaaaaab36","aaaaaaaaaab37","aaaaaaaaaab38","aaaaaaaaaab39","aaaaaaaaaab40","aaaaaaaaaab41","aaaaaaaaaab42","aaaaaaaaaab43","aaaaaaaaaab44","aaaaaaaaaab45","aaaaaaaaaab46","aaaaaaaaaab47","aaaaaaaaaab48","aaaaaaaaaab49","aaaaaaaaaab50","aaaaaaaaaab51","aaaaaaaaaab52","aaaaaaaaaab53","aaaaaaaaaab54","aaaaaaaaaab55","aaaaaaaaaab56","aaaaaaaaaab57","aaaaaaaaaab58","aaaaaaaaaab59","aaaaaaaaaab60","aaaaaaaaaab61","aaaaaaaaaab62","aaaaaaaaaab63","aaaaaaaaaab64","aaaaaaaaaab65","aaaaaaaaaab66","aaaaaaaaaab67","aaaaaaaaaab68","aaaaaaaaaab69","aaaaaaaaaab70","aaaaaaaaaab71","aaaaaaaaaab72","aaaaaaaaaab73","aaaaaaaaaab74","aaaaaaaaaab75","aaaaaaaaaab76","aaaaaaaaaab77","aaaaaaaaaab78","aaaaaaaaaab79","aaaaaaaaaab80","aaaaaaaaaab81","aaaaaaaaaab82","aaaaaaaaaab83","aaaaaaaaaab84","aaaaaaaaaab85","aaaaaaaaaab86","aaaaaaaaaab87","aaaaaaaaaab88","aaaaaaaaaab89","aaaaaaaaaab90","aaaaaaaaaab91","aaaaaaaaaab92","aaaaaaaaaab93","aaaaaaaaaab94","aaaaaaaaaab95","aaaaaaaaaab96","aaaaaaaaaab97","aaaaaaaaaab98","aaaaaaaaaab99"],"searchWord":"aaaaaaaaaab"}
⏱ Performance - must finish in 2000ms

n=100 products each length ~11, searchWord length=11; O(n*k + m) expected to complete within 2s.

Practice

(1/5)
1. Given the following code snippet for finding concatenated words, what is the value of memo after calling dfs('catsdog', 0) on the input ['cat', 'cats', 'dog', 'catsdog']?
easy
A. {0: True, 3: True, 4: True, 7: True}
B. {0: True, 3: True, 4: False}
C. {0: True, 3: False, 4: True}
D. {0: False, 3: True, 4: True}

Solution

  1. Step 1: Trace dfs('catsdog', 0) calls and memo updates

    Start=0: check prefixes 'cat'(0-3), 'cats'(0-4). 'cat' leads to dfs(3), 'cats' leads to dfs(4).
  2. Step 2: Evaluate dfs(3) and dfs(4)

    dfs(3) checks 'sdog' prefix - no match, returns False; dfs(4) checks 'dog' prefix - matches 'dog', dfs(7) returns True; memo[4]=True, memo[3]=False, memo[0]=True.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Memo correctly records True at 0 and 4, False at 3 [OK]
Hint: Memo stores start indices where suffix can form concatenation [OK]
Common Mistakes:
  • Confusing indices or forgetting to memoize False results
2. Consider the following Python code implementing the optimal StreamChecker. Given the words ["cd", "f", "kl"], what is the return value of the query sequence: query('a'), query('b'), query('c'), query('d')? Specifically, what does query('d') return?
class TrieNode:
    def __init__(self):
        self.children = {}
        self.is_word = False

class StreamChecker:
    def __init__(self, words):
        self.root = TrieNode()
        self.max_len = max(len(w) for w in words)
        self.stream = []
        for word in words:
            node = self.root
            for ch in reversed(word):
                if ch not in node.children:
                    node.children[ch] = TrieNode()
                node = node.children[ch]
            node.is_word = True

    def query(self, letter):
        self.stream.append(letter)
        if len(self.stream) > self.max_len:
            self.stream.pop(0)
        node = self.root
        for ch in reversed(self.stream):
            if ch not in node.children:
                return False
            node = node.children[ch]
            if node.is_word:
                return True
        return False

sc = StreamChecker(["cd", "f", "kl"])
print(sc.query('a'))
print(sc.query('b'))
print(sc.query('c'))
print(sc.query('d'))
easy
A. False
B. True
C. Raises an exception
D. None

Solution

  1. Step 1: Trace the stream buffer after queries

    After queries 'a', 'b', 'c', 'd', the stream buffer contains ['a','b','c','d'], but max_len=2, so oldest letters are popped. After 'c', stream=['b','c'], after 'd', stream=['c','d'].
  2. Step 2: Traverse trie with reversed stream

    For query('d'), reversed stream is ['d','c']. Trie has reversed words: 'dc' for 'cd'. Traversing 'd' then 'c' hits is_word=True at 'c' node, so returns True. However, the query sequence is query('a'), query('b'), query('c'), query('d'). The query('c') returns False because 'c' alone is not a word. The query('d') returns True because 'cd' is in the dictionary and the stream buffer contains ['c','d'].
  3. Step 3: Check query('d') return value

    Since the query('d') returns True, the correct answer is True.
  4. Final Answer:

    Option B -> Option B
  5. Quick Check:

    Stream buffer limited to max word length matches 'cd' suffix [OK]
Hint: Stream buffer limited to max word length [OK]
Common Mistakes:
  • Not limiting stream buffer size
  • Not reversing words in trie
  • Returning false too early
3. Consider the following snippet from the optimal Trie + DFS solution for Word Search II. Given the board and words below, what is the final list of words found? Board: [['o','a','a','n'], ['e','t','a','e'], ['i','h','k','r'], ['i','f','l','v']] Words: ["oath", "pea", "eat", "rain"]
from typing import List

class TrieNode:
    def __init__(self):
        self.children = {}
        self.word = None

class Solution:
    def buildTrie(self, words):
        root = TrieNode()
        for w in words:
            node = root
            for c in w:
                if c not in node.children:
                    node.children[c] = TrieNode()
                node = node.children[c]
            node.word = w
        return root

    def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
        root = self.buildTrie(words)
        rows, cols = len(board), len(board[0])
        result = []

        def dfs(r, c, node):
            if r < 0 or r >= rows or c < 0 or c >= cols:
                return
            char = board[r][c]
            if char == '#' or char not in node.children:
                return
            node = node.children[char]
            if node.word:
                result.append(node.word)
                node.word = None
            board[r][c] = '#'
            dfs(r+1, c, node)
            dfs(r-1, c, node)
            dfs(r, c+1, node)
            dfs(r, c-1, node)
            board[r][c] = char

        for r in range(rows):
            for c in range(cols):
                dfs(r, c, root)
        return result
easy
A. ["eat"]
B. ["pea", "rain"]
C. ["oath", "pea", "eat", "rain"]
D. ["oath", "eat"]

Solution

  1. Step 1: Trace DFS starting at 'o' (0,0)

    "oath" is found by following o->a->t->h path on the board.
  2. Step 2: Trace DFS starting at 'e' (1,0)

    "eat" is found by e->a->t path on the board.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    "pea" and "rain" cannot be formed on the board [OK]
Hint: Only words fully traceable on board are found [OK]
Common Mistakes:
  • Including words not present on board
  • Missing words found by DFS
  • Not handling visited cells correctly
4. Consider the following buggy code snippet for the longest word in dictionary problem. Which line contains the subtle bug that can cause incorrect results?
medium
A. Line: queue.append(child) without checking if child.word is not None
B. Line: for ch in sorted(node.children.keys())
C. Line: node.word = word in insert method
D. Line: trie.insert(word) in the for loop

Solution

  1. Step 1: Identify enqueue condition

    The BFS queue should only include nodes representing complete words (child.word != None) to ensure all prefixes are valid.
  2. Step 2: Locate the bug

    The code enqueues all children regardless of whether they represent complete words, allowing invalid prefixes to be considered, breaking the prefix condition.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Enqueueing invalid prefix nodes causes incorrect longest word [OK]
Hint: Only enqueue nodes with complete words in BFS [OK]
Common Mistakes:
  • Enqueueing all children regardless of word completion
  • Misplacing word assignment in insert
  • Sorting children incorrectly
5. Suppose the problem changes: you want to find the maximum XOR of two numbers in an array, but now numbers can be negative 32-bit integers. Which modification to the bitwise trie approach is necessary to handle negative numbers correctly?
hard
A. Use two's complement 32-bit representation and treat bits as unsigned during trie insertion and traversal
B. Ignore sign bit and only build trie from absolute values of numbers
C. Use 64-bit representation to store numbers in trie to avoid sign issues
D. Preprocess numbers by adding a large constant to make all numbers positive before building trie

Solution

  1. Step 1: Understand representation of negative numbers

    Negative integers in 32-bit are stored in two's complement form, which can be treated as unsigned bit patterns for trie operations.
  2. Step 2: Modify trie insertion and traversal

    Insert and traverse bits as unsigned 32-bit integers, including the sign bit, to correctly handle negative numbers.
  3. Step 3: Avoid incorrect approaches

    Using 64-bit or adding constants changes problem semantics; ignoring sign bit loses information.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    Two's complement allows uniform bitwise trie handling of negative numbers [OK]
Hint: Two's complement bits can be treated as unsigned [OK]
Common Mistakes:
  • Ignoring sign bit or converting to absolute values
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard