Search Suggestions System

MediumTrie · Sorting · Two Pointers🧩 TrieLeetCode #1268 ↗Updated

Problem

You get a list of distinct product names and a searchWord typed one letter at a time. After each letter, suggest up to three products that start with the text typed so far, choosing the lexicographically smallest ones. Return the list of suggestion lists, one per typed letter.
Input[mouse,mobile,monitor,mousepad], "mou"Output[[mobile,monitor,mouse], [mobile,monitor,mouse], [mouse,mousepad]]
Input[havana], "tat"Output[[], [], []]

1 ≤ n ≤ 1000  ·  total length of products ≤ 2·104  ·  products are unique  ·  1 ≤ searchWord.length ≤ 1000  ·  lowercase only

Try it yourself

Java
class Solution {
    public List<List<String>> suggestedProducts(String[] products, String searchWord) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
After sorting, all products sharing a prefix form one contiguous block, and the answer is simply the first three entries of that block. Each extra typed letter only shrinks the block, so its two ends can move inward monotonically.
PatternTrie

Instinct Many words, shared prefixes, and questions like "starts with", autocomplete, wildcard match or "search a board for all these words" - build a prefix tree.

Memory hack Words share their beginnings, so store each beginning once - walk one letter per step, and an end flag marks where a real word stops.

Open the Trie guide →

Approaches

Brute ForceSort + Scan for Every Prefix

Time O(L·n log n + n·m2)Space O(n)

Sort once so the first matches met are the smallest. For each of the m prefixes, scan all n products with startsWith and keep the first three. L = max product length, m = searchWord length.

Java
public List<List<String>> suggestedProducts(String[] products, String searchWord) {
    Arrays.sort(products);
    List<List<String>> result = new ArrayList<>();
    for (int i = 1; i <= searchWord.length(); i++) {
        String prefix = searchWord.substring(0, i);
        List<String> suggestions = new ArrayList<>();
        for (String p : products) {
            if (p.startsWith(prefix)) suggestions.add(p);
            if (suggestions.size() == 3) break;
        }
        result.add(suggestions);
    }
    return result;
}

Simple and correct, but rescans every product for every typed letter.

At a glance

LevelApproachTimeSpace
Brute ForceSort + Scan for Every PrefixO(L·n log n + n·m2)O(n)
BetterTrie Storing Top-3 per NodeO(L·n log n + S + m)O(26·S)
OptimalSort + Shrinking Two PointersO(L·n log n + n + m)O(n)
Common pitfalls
  • Forgetting to sort — “smallest three” is about lexicographic order.
  • Stopping early after a prefix has no match — still add an empty list for every remaining letter.
  • Not checking length() <= i before charAt(i) — index out of bounds.
Interview tips
  • Ask whether the product list changes; a static list favours sort + pointers, a dynamic one a trie.
  • Explain why the matching block stays contiguous in sorted order.
  • Mention that storing top-3 lists in trie nodes trades memory for O(1) per keystroke.
Pattern
Sorted prefix range / Trie → autocomplete-style queries for the k smallest strings with a prefix.
My notes saved in this browser