Bird
Raised Fist0
Interview PreptriesmediumAmazonGoogleFacebook

Search Suggestions System (Autocomplete)

Choose your preparation mode4 modes available
🎯
Search Suggestions System (Autocomplete)
mediumTRIEAmazonGoogleFacebook

Imagine typing a search query on your favorite shopping site and instantly seeing suggested products as you type. This problem simulates building that autocomplete feature efficiently.

💡 This problem is about efficiently suggesting the top 3 lexicographically smallest products that start with the current search prefix. Beginners often struggle because naive substring matching is too slow for large inputs, and understanding how tries can speed up prefix queries is key.
📋
Problem Statement

Given an array of strings products and a string searchWord, design a system that suggests at most three product names from products after each character of searchWord is typed. Suggested products should have a common prefix with the searchWord. If there are more than three products with a common prefix, return the three lexicographically minimum products.

1 ≤ products.length ≤ 10^51 ≤ products[i].length ≤ 30001 ≤ searchWord.length ≤ 1000All strings consist of lowercase English letters.Products may contain duplicates.
💡
Example
Input{"products":["mobile","mouse","moneypot","monitor","mousepad"],"searchWord":"mouse"}
Outputmobilemoneypotmonitormobilemoneypotmonitormousemousepadmousemousepadmousemousepad

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.

  • Empty products array → return empty lists for all prefixes
  • searchWord with characters not present in any product → empty suggestions from that point onward
  • Products with identical names → suggestions include duplicates if they appear
  • Products with very long strings but short searchWord → ensure performance and correctness
⚠️
Common Mistakes
Not sorting products before building trie or binary searching

Suggestions are not lexicographically ordered, failing problem requirements

✅ Always sort products lexicographically before processing

Collecting more than three suggestions per prefix node

Excess memory usage and slower queries

✅ Limit suggestions stored at each trie node to three

Using startsWith check on all products for each prefix in brute force

Leads to time limit exceeded on large inputs

✅ Use binary search or trie to avoid scanning all products repeatedly

Not handling the case when prefix is not found in trie

Null pointer exceptions or incorrect empty suggestions

✅ Check if current node exists before traversing children; append empty list if not

Appending suggestions directly without copying in Java or Python

Modifications to suggestions in later steps affect previous results

✅ Create new list copies when adding to result to avoid aliasing

🧠
Brute Force (Sorting + Prefix Filtering)
💡 This approach exists to establish a baseline and understand the problem constraints. It uses straightforward sorting and filtering without advanced data structures, helping beginners grasp the core requirements before optimization.

Intuition

Sort the products lexicographically. For each prefix of searchWord, scan through the sorted list and collect up to three products that start with that prefix.

Algorithm

  1. Sort the products array lexicographically.
  2. For each prefix of searchWord from length 1 to n:
  3. Iterate over the sorted products and collect up to three products starting with the prefix.
  4. Add the collected list to the result.
💡 The nested iteration over products for each prefix is straightforward but inefficient, which is why this approach is a starting point.
</>
Code
from typing import List

def suggestedProducts(products: List[str], searchWord: str) -> List[List[str]]:
    products.sort()
    result = []
    prefix = ''
    for ch in searchWord:
        prefix += ch
        suggestions = []
        for product in products:
            if product.startswith(prefix):
                suggestions.append(product)
                if len(suggestions) == 3:
                    break
        result.append(suggestions)
    return result

# Driver code
if __name__ == '__main__':
    products = ["mobile","mouse","moneypot","monitor","mousepad"]
    searchWord = "mouse"
    print(suggestedProducts(products, searchWord))
Line Notes
products.sort()Sort products lexicographically to ensure suggestions are in order
for ch in searchWord:Build prefixes incrementally for each character typed
if product.startswith(prefix):Check if current product matches the prefix
if len(suggestions) == 3:Limit suggestions to top 3 to meet problem requirements
import java.util.*;

public class Solution {
    public List<List<String>> suggestedProducts(String[] products, String searchWord) {
        Arrays.sort(products);
        List<List<String>> result = new ArrayList<>();
        String prefix = "";
        for (char ch : searchWord.toCharArray()) {
            prefix += ch;
            List<String> suggestions = new ArrayList<>();
            for (String product : products) {
                if (product.startsWith(prefix)) {
                    suggestions.add(product);
                    if (suggestions.size() == 3) break;
                }
            }
            result.add(suggestions);
        }
        return result;
    }

    public static void main(String[] args) {
        Solution sol = new Solution();
        String[] products = {"mobile","mouse","moneypot","monitor","mousepad"};
        String searchWord = "mouse";
        System.out.println(sol.suggestedProducts(products, searchWord));
    }
}
Line Notes
Arrays.sort(products);Sort products lexicographically for ordered suggestions
for (char ch : searchWord.toCharArray()) {Iterate over each character to build prefixes
if (product.startsWith(prefix)) {Check if product matches current prefix
if (suggestions.size() == 3) break;Stop after collecting three suggestions
#include <bits/stdc++.h>
using namespace std;

class Solution {
public:
    vector<vector<string>> suggestedProducts(vector<string>& products, string searchWord) {
        sort(products.begin(), products.end());
        vector<vector<string>> result;
        string prefix = "";
        for (char ch : searchWord) {
            prefix += ch;
            vector<string> suggestions;
            for (auto& product : products) {
                if (product.compare(0, prefix.size(), prefix) == 0) {
                    suggestions.push_back(product);
                    if (suggestions.size() == 3) break;
                }
            }
            result.push_back(suggestions);
        }
        return result;
    }
};

int main() {
    Solution sol;
    vector<string> products = {"mobile","mouse","moneypot","monitor","mousepad"};
    string searchWord = "mouse";
    auto res = sol.suggestedProducts(products, searchWord);
    for (auto& vec : res) {
        cout << "[";
        for (int i = 0; i < (int)vec.size(); ++i) {
            cout << vec[i];
            if (i != (int)vec.size() - 1) cout << ",";
        }
        cout << "]\n";
    }
    return 0;
}
Line Notes
sort(products.begin(), products.end());Sort products lexicographically for ordered suggestions
for (char ch : searchWord) {Build prefixes character by character
if (product.compare(0, prefix.size(), prefix) == 0) {Check if product starts with prefix
if (suggestions.size() == 3) break;Limit to top 3 suggestions
var suggestedProducts = function(products, searchWord) {
    products.sort();
    const result = [];
    let prefix = '';
    for (const ch of searchWord) {
        prefix += ch;
        const suggestions = [];
        for (const product of products) {
            if (product.startsWith(prefix)) {
                suggestions.push(product);
                if (suggestions.length === 3) break;
            }
        }
        result.push(suggestions);
    }
    return result;
};

// Driver code
const products = ["mobile","mouse","moneypot","monitor","mousepad"];
const searchWord = "mouse";
console.log(suggestedProducts(products, searchWord));
Line Notes
products.sort();Sort products lexicographically for consistent suggestion order
for (const ch of searchWord) {Iterate over each character to build prefixes
if (product.startsWith(prefix)) {Check if product matches current prefix
if (suggestions.length === 3) break;Stop after collecting three suggestions
⏱
Complexity
TimeO(m * n * k) where m = length of searchWord, n = number of products, k = average length of product prefix comparison
SpaceO(n * k) for sorting and output storage

For each prefix (m prefixes), we scan all products (n) and check prefix match (up to k chars). Sorting costs O(n log n * k).

💡 For n=1000 products and searchWord length m=10, this means up to 10*1000=10,000 prefix checks, which is slow but manageable for small inputs.
Interview Verdict: TLE on large inputs / Use only to introduce

This approach is too slow for large inputs but helps understand the problem and why optimization is needed.

🧠
Binary Search on Sorted Products
💡 This approach improves efficiency by using binary search to find the starting index of products matching each prefix, reducing unnecessary scans.

Intuition

Sort products lexicographically. For each prefix, use binary search to find the first product that could match the prefix, then collect up to three products from that point if they match.

Algorithm

  1. Sort the products lexicographically.
  2. For each prefix of searchWord:
  3. Use binary search to find the leftmost product that matches or could match the prefix.
  4. Collect up to three products starting from that index that match the prefix.
💡 Binary search narrows down the search space drastically, making prefix matching efficient.
</>
Code
from typing import List
import bisect

def suggestedProducts(products: List[str], searchWord: str) -> List[List[str]]:
    products.sort()
    result = []
    prefix = ''
    for ch in searchWord:
        prefix += ch
        i = bisect.bisect_left(products, prefix)
        suggestions = []
        for j in range(i, min(i + 3, len(products))):
            if products[j].startswith(prefix):
                suggestions.append(products[j])
            else:
                break
        result.append(suggestions)
    return result

# Driver code
if __name__ == '__main__':
    products = ["mobile","mouse","moneypot","monitor","mousepad"]
    searchWord = "mouse"
    print(suggestedProducts(products, searchWord))
Line Notes
products.sort()Sort products lexicographically for binary search
i = bisect.bisect_left(products, prefix)Find insertion point for prefix to start suggestions
for j in range(i, min(i + 3, len(products))):Check up to three products from found index
if products[j].startswith(prefix):Confirm product matches prefix before adding
import java.util.*;

public class Solution {
    public List<List<String>> suggestedProducts(String[] products, String searchWord) {
        Arrays.sort(products);
        List<List<String>> result = new ArrayList<>();
        String prefix = "";
        for (char ch : searchWord.toCharArray()) {
            prefix += ch;
            int i = leftBound(products, prefix);
            List<String> suggestions = new ArrayList<>();
            for (int j = i; j < Math.min(i + 3, products.length); j++) {
                if (products[j].startsWith(prefix)) {
                    suggestions.add(products[j]);
                } else {
                    break;
                }
            }
            result.add(suggestions);
        }
        return result;
    }

    private int leftBound(String[] products, String prefix) {
        int left = 0, right = products.length;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (products[mid].compareTo(prefix) < 0) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }

    public static void main(String[] args) {
        Solution sol = new Solution();
        String[] products = {"mobile","mouse","moneypot","monitor","mousepad"};
        String searchWord = "mouse";
        System.out.println(sol.suggestedProducts(products, searchWord));
    }
}
Line Notes
Arrays.sort(products);Sort products for binary search
int i = leftBound(products, prefix);Find leftmost index where prefix could be inserted
if (products[j].startsWith(prefix)) {Check if product matches prefix before adding
while (left < right) {Binary search loop to find insertion point
#include <bits/stdc++.h>
using namespace std;

class Solution {
public:
    vector<vector<string>> suggestedProducts(vector<string>& products, string searchWord) {
        sort(products.begin(), products.end());
        vector<vector<string>> result;
        string prefix = "";
        for (char ch : searchWord) {
            prefix += ch;
            auto it = lower_bound(products.begin(), products.end(), prefix);
            vector<string> suggestions;
            for (int i = 0; i < 3 && it + i != products.end(); ++i) {
                if ((it + i)->compare(0, prefix.size(), prefix) == 0) {
                    suggestions.push_back(*(it + i));
                } else {
                    break;
                }
            }
            result.push_back(suggestions);
        }
        return result;
    }
};

int main() {
    Solution sol;
    vector<string> products = {"mobile","mouse","moneypot","monitor","mousepad"};
    string searchWord = "mouse";
    auto res = sol.suggestedProducts(products, searchWord);
    for (auto& vec : res) {
        cout << "[";
        for (int i = 0; i < (int)vec.size(); ++i) {
            cout << vec[i];
            if (i != (int)vec.size() - 1) cout << ",";
        }
        cout << "]\n";
    }
    return 0;
}
Line Notes
sort(products.begin(), products.end());Sort products for binary search
auto it = lower_bound(products.begin(), products.end(), prefix);Find first product not less than prefix
if ((it + i)->compare(0, prefix.size(), prefix) == 0) {Check prefix match before adding
for (int i = 0; i < 3 && it + i != products.end(); ++i) {Collect up to three suggestions
var suggestedProducts = function(products, searchWord) {
    products.sort();
    const result = [];
    let prefix = '';
    for (const ch of searchWord) {
        prefix += ch;
        let left = 0, right = products.length;
        while (left < right) {
            const mid = Math.floor((left + right) / 2);
            if (products[mid] < prefix) left = mid + 1;
            else right = mid;
        }
        const suggestions = [];
        for (let i = left; i < Math.min(left + 3, products.length); i++) {
            if (products[i].startsWith(prefix)) suggestions.push(products[i]);
            else break;
        }
        result.push(suggestions);
    }
    return result;
};

// Driver code
const products = ["mobile","mouse","moneypot","monitor","mousepad"];
const searchWord = "mouse";
console.log(suggestedProducts(products, searchWord));
Line Notes
products.sort();Sort products for binary search
while (left < right) {Binary search to find insertion point for prefix
if (products[i].startsWith(prefix)) suggestions.push(products[i]);Add matching products to suggestions
for (let i = left; i < Math.min(left + 3, products.length); i++) {Limit suggestions to three
⏱
Complexity
TimeO(m * log n + m * 3 * k) where m = length of searchWord, n = number of products, k = prefix length
SpaceO(n * k) for sorting and output

Binary search reduces scanning from O(n) to O(log n) per prefix. Checking up to 3 products per prefix is constant.

💡 For n=1000 and m=10, this means about 10*log2(1000)=100 binary search steps plus a few prefix checks, much faster than brute force.
Interview Verdict: Accepted / Efficient for large inputs

This approach is a practical improvement and often acceptable in interviews if trie is not required.

🧠
Trie with DFS Collection of Top 3 Suggestions
💡 This approach uses a trie data structure to efficiently store products and retrieve top 3 lexicographically smallest suggestions for each prefix, which is optimal for large datasets.

Intuition

Build a trie from all products. Each node stores up to three lexicographically smallest products passing through it. For each prefix of searchWord, traverse the trie and return the stored suggestions.

Algorithm

  1. Sort products lexicographically to ensure insertion order.
  2. Build a trie where each node stores up to three suggestions passing through it.
  3. For each prefix of searchWord, traverse the trie nodes corresponding to the prefix.
  4. Collect and return the stored suggestions at each node.
💡 The key is storing top 3 suggestions at each node during insertion to avoid repeated searches later.
</>
Code
from typing import List

class TrieNode:
    def __init__(self):
        self.children = {}
        self.suggestions = []

class Solution:
    def suggestedProducts(self, products: List[str], searchWord: str) -> List[List[str]]:
        root = TrieNode()
        products.sort()

        # Build trie
        for product in products:
            node = root
            for ch in product:
                if ch not in node.children:
                    node.children[ch] = TrieNode()
                node = node.children[ch]
                if len(node.suggestions) < 3:
                    node.suggestions.append(product)

        result = []
        node = root
        for ch in searchWord:
            if node and ch in node.children:
                node = node.children[ch]
                result.append(node.suggestions[:])
            else:
                node = None
                result.append([])
        return result

# Driver code
if __name__ == '__main__':
    sol = Solution()
    products = ["mobile","mouse","moneypot","monitor","mousepad"]
    searchWord = "mouse"
    print(sol.suggestedProducts(products, searchWord))
Line Notes
products.sort()Sort products to ensure lexicographic order for suggestions
if ch not in node.children:Create child node if it doesn't exist
if len(node.suggestions) < 3:Store up to three suggestions per node to limit memory
if node and ch in node.children:Traverse trie nodes matching prefix characters
import java.util.*;

class TrieNode {
    Map<Character, TrieNode> children = new HashMap<>();
    List<String> suggestions = new ArrayList<>();
}

public class Solution {
    public List<List<String>> suggestedProducts(String[] products, String searchWord) {
        Arrays.sort(products);
        TrieNode root = new TrieNode();

        for (String product : products) {
            TrieNode node = root;
            for (char ch : product.toCharArray()) {
                node.children.putIfAbsent(ch, new TrieNode());
                node = node.children.get(ch);
                if (node.suggestions.size() < 3) {
                    node.suggestions.add(product);
                }
            }
        }

        List<List<String>> result = new ArrayList<>();
        TrieNode node = root;
        for (char ch : searchWord.toCharArray()) {
            if (node != null && node.children.containsKey(ch)) {
                node = node.children.get(ch);
                result.add(new ArrayList<>(node.suggestions));
            } else {
                node = null;
                result.add(new ArrayList<>());
            }
        }
        return result;
    }

    public static void main(String[] args) {
        Solution sol = new Solution();
        String[] products = {"mobile","mouse","moneypot","monitor","mousepad"};
        String searchWord = "mouse";
        System.out.println(sol.suggestedProducts(products, searchWord));
    }
}
Line Notes
Arrays.sort(products);Sort products to maintain lexicographic order
node.children.putIfAbsent(ch, new TrieNode());Create child node if missing
if (node.suggestions.size() < 3) {Limit suggestions stored per node to three
if (node != null && node.children.containsKey(ch)) {Traverse trie nodes for prefix
#include <bits/stdc++.h>
using namespace std;

struct TrieNode {
    unordered_map<char, TrieNode*> children;
    vector<string> suggestions;
};

class Solution {
public:
    vector<vector<string>> suggestedProducts(vector<string>& products, string searchWord) {
        sort(products.begin(), products.end());
        TrieNode* root = new TrieNode();

        for (const string& product : products) {
            TrieNode* node = root;
            for (char ch : product) {
                if (!node->children.count(ch))
                    node->children[ch] = new TrieNode();
                node = node->children[ch];
                if ((int)node->suggestions.size() < 3)
                    node->suggestions.push_back(product);
            }
        }

        vector<vector<string>> result;
        TrieNode* node = root;
        for (char ch : searchWord) {
            if (node && node->children.count(ch)) {
                node = node->children[ch];
                result.push_back(node->suggestions);
            } else {
                node = nullptr;
                result.push_back({});
            }
        }
        return result;
    }
};

int main() {
    Solution sol;
    vector<string> products = {"mobile","mouse","moneypot","monitor","mousepad"};
    string searchWord = "mouse";
    auto res = sol.suggestedProducts(products, searchWord);
    for (auto& vec : res) {
        cout << "[";
        for (int i = 0; i < (int)vec.size(); ++i) {
            cout << vec[i];
            if (i != (int)vec.size() - 1) cout << ",";
        }
        cout << "]\n";
    }
    return 0;
}
Line Notes
sort(products.begin(), products.end());Sort products to ensure lexicographic insertion order
if (!node->children.count(ch))Create child node if missing
if ((int)node->suggestions.size() < 3)Store up to three suggestions per node
if (node && node->children.count(ch))Traverse trie nodes for prefix characters
class TrieNode {
    constructor() {
        this.children = new Map();
        this.suggestions = [];
    }
}

var suggestedProducts = function(products, searchWord) {
    products.sort();
    const root = new TrieNode();

    for (const product of products) {
        let node = root;
        for (const ch of product) {
            if (!node.children.has(ch)) {
                node.children.set(ch, new TrieNode());
            }
            node = node.children.get(ch);
            if (node.suggestions.length < 3) {
                node.suggestions.push(product);
            }
        }
    }

    const result = [];
    let node = root;
    for (const ch of searchWord) {
        if (node && node.children.has(ch)) {
            node = node.children.get(ch);
            result.push(node.suggestions.slice());
        } else {
            node = null;
            result.push([]);
        }
    }
    return result;
};

// Driver code
const products = ["mobile","mouse","moneypot","monitor","mousepad"];
const searchWord = "mouse";
console.log(suggestedProducts(products, searchWord));
Line Notes
products.sort();Sort products to maintain lexicographic order
if (!node.children.has(ch)) {Create child node if missing
if (node.suggestions.length < 3) {Limit suggestions stored per node to three
if (node && node.children.has(ch)) {Traverse trie nodes for each prefix character
⏱
Complexity
TimeO(n * k + m) where n = number of products, k = average length of product, m = length of searchWord
SpaceO(n * k) for trie storage and suggestions

Building the trie takes O(n*k). Querying for each prefix is O(m). Storing only top 3 suggestions per node limits memory.

💡 For 100,000 products averaging length 10, building the trie is feasible and querying is very fast compared to scanning.
Interview Verdict: Accepted / Optimal for large inputs

This is the best approach for large datasets and is expected in interviews for trie pattern problems.

📊
All Approaches - One-Glance Tradeoffs
💡 In interviews, coding the trie approach is ideal for trie pattern problems, but knowing brute force and binary search helps explain your thought process.
ApproachTimeSpaceStack RiskReconstructUse In Interview
1. Brute ForceO(m * n * k)O(n * k)NoN/AMention only - never code
2. Binary SearchO(m * log n + m * 3 * k)O(n * k)NoN/AGood fallback if trie is unfamiliar
3. Trie with Top 3 SuggestionsO(n * k + m)O(n * k)NoYesOptimal - code this if comfortable
💼
Interview Strategy
💡 Use this guide to understand the problem deeply, practice coding each approach, and prepare to explain tradeoffs clearly in interviews.

How to Present

Step 1: Clarify problem requirements and constraints.Step 2: Describe the brute force approach and its limitations.Step 3: Introduce binary search optimization and explain how it improves performance.Step 4: Present the trie-based solution as the optimal approach.Step 5: Discuss time and space complexities and tradeoffs.Step 6: Code the chosen approach and test with examples.

Time Allocation

Clarify: 2min → Approach: 5min → Code: 15min → Test: 3min. Total ~25min

What the Interviewer Tests

The interviewer tests your understanding of prefix search, ability to optimize naive solutions, knowledge of tries and binary search, and coding accuracy.

Common Follow-ups

  • How would you handle case-insensitive search? → Normalize input to lowercase.
  • What if you need to support dynamic insertions? → Use a trie with insert method and update suggestions.
💡 Follow-ups often test your ability to adapt the solution to real-world variations and dynamic data.
🔍
Pattern Recognition

When to Use

1) Need to find strings with common prefixes repeatedly, 2) Need lexicographically ordered suggestions, 3) Large input size where scanning is too slow, 4) Problem mentions autocomplete or prefix search

Signature Phrases

suggest at most three product namescommon prefix with searchWordlexicographically minimum products

NOT This Pattern When

Substring search problems or suffix-based problems which require suffix trees or arrays

Similar Problems

Implement Trie (Prefix Tree) - foundational trie constructionDesign Search Autocomplete System - similar autocomplete with dynamic inputWord Squares - uses trie for prefix pruning

Practice

(1/5)
1. Examine the following buggy search method for the WordDictionary implemented with a trie. Which line contains the subtle bug that causes incorrect search results for patterns with '.' wildcard?
def search(self, word: str) -> bool:
    stack = [(0, self.root)]
    while stack:
        index, node = stack.pop()
        if index == len(word):
            if node.is_end:
                return True
            continue
        ch = word[index]
        if ch == '.':
            for child in node.children:
                stack.append((index + 1, child))
        else:
            if ch in node.children:
                stack.append((index + 1, node.children[ch]))
    return False
medium
A. Line with 'stack = [(0, self.root)]'
B. Line with 'for child in node.children:'
C. Line with 'if node.is_end:'
D. Line with 'if ch in node.children:'

Solution

  1. Step 1: Identify how children are iterated for '.' wildcard

    The code uses 'for child in node.children:', which iterates over keys (characters), not child nodes.
  2. Step 2: Understand impact of iterating keys instead of nodes

    Appending keys instead of TrieNode objects causes incorrect stack entries and search failure.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Must iterate over node.children.values() to get child nodes [OK]
Hint: Iterate node.children.values(), not keys [OK]
Common Mistakes:
  • Iterating keys instead of child nodes
  • Forgetting to mark is_end
  • Misplacing base case check
2. What is the worst-case time complexity of searching for a word of length m in a trie implemented with a hash map for children, assuming the alphabet size is large and the trie contains n words?
medium
A. O(m) because each character leads to a hash map lookup
B. O(m * log n) due to hash map lookup cost increasing with n
C. O(n * m) because each search may scan all words
D. O(m * |alphabet|) because each character requires scanning all children

Solution

  1. Step 1: Identify search steps in trie

    Search traverses nodes for each character in the word, performing a hash map lookup per character.
  2. Step 2: Analyze hash map lookup cost

    Hash map lookup is O(1) average, so total time is O(m) where m is word length.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Search time depends on word length, not number of stored words [OK]
Hint: Trie search time depends on word length, not number of words [OK]
Common Mistakes:
  • Confusing trie search with scanning all words (O(n*m))
3. What is the time complexity of the optimal trie + BFS approach for finding the longest word in a dictionary with n words, each of average length m?
medium
A. O(n * m + n * 26) because building trie takes O(n*m) and BFS visits each node once
B. O(n * m * 26) since BFS explores all children for each character
C. O(n * m^2) due to checking all prefixes for each word
D. O(n * m log n) due to sorting children at each node during BFS

Solution

  1. Step 1: Analyze trie construction

    Inserting n words of length m takes O(n * m) time as each character is processed once.
  2. Step 2: Analyze BFS traversal

    BFS visits each node once; each node has up to 26 children, so total BFS cost is O(n * 26) which is O(n).
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Trie build + BFS traversal sum to O(n*m + n*26) [OK]
Hint: Trie build O(n*m), BFS O(n*26) combined [OK]
Common Mistakes:
  • Confusing BFS cost as O(n*m*26)
  • Forgetting BFS visits each node once
  • Assuming sorting children adds log factor per node
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. If the problem is modified so that words can be concatenated using the same shorter word multiple times (reuse allowed), which change to the Trie + DFS + memoization approach is necessary to correctly find all concatenated words?
hard
A. Keep memoization but ensure that the base case allows concatenations with repeated words
B. Remove memoization to allow repeated exploration of the same indices
C. No change needed; current memoization handles reuse correctly
D. Modify DFS to allow revisiting the same start index multiple times without memoization

Solution

  1. Step 1: Understand reuse means words can be concatenated multiple times

    Memoization caches results per start index; reuse is allowed if base case and DFS logic permit repeated words.
  2. Step 2: Adjust base case and DFS to allow repeated words but keep memoization for efficiency

    Memoization should remain to avoid exponential calls; base case must allow concatenations with repeated words.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Memoization remains; base case and DFS logic adapt to reuse [OK]
Hint: Memoization is key; only base case and DFS logic need adjustment for reuse [OK]
Common Mistakes:
  • Removing memoization causes TLE
  • Ignoring base case changes for reuse
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