Talentd
FleetCode
Make and follow sheets.Sign in

Search Suggestions System solution and explanation

MediumArrayBinary SearchHeap (Priority Queue)Sorting8 min read65.1% acceptanceUpdated 9 Apr 2026
Search Suggestions System - Leetcode 1268 - PythonNeetCode · 13:16 · 60K viewsWatch on YouTube
9 more videos on this problem
  1. Search Suggestions System - Leetcode 1268 - PythonNeetCode · 13:16 · 60K views
  2. LeetCode 1268. Search Suggestions System - Interview Prep Ep 103Fisher Coder · 20:34 · 8K views
  3. Search Suggestions System | Leetcode 1268 | Trie | Binary SeachAyushi Sharma · 24:16 · 6K views
  4. LeetCode 1268. Search Suggestions System Explanation and Solutionhappygirlzt · 11:59 · 5K views
  5. Leetcode - Search Suggestions System (Python)Timothy H Chang · 4:55 · 3K views
  6. Search Suggestions System | LeetCode 1268 | Coders CampCoders Camp · 10:17 · 1K views
  7. LeetCode 1268 Search Suggestions System - Google, Amazon, Apple Interview Question SolvedAlgorithmicIQ · 18:07 · 815 views
  8. Leetcode 1268 Search Suggestions System | TreeMap | Checkout Coding Decoded SDE SheetCoding Decoded · 2:01 · 402 views
  9. Search Suggestions System - LeetCode 1268 - PythonAlpha-Code · 17:38 · 219 views
  10. Search Suggestions System - Leetcode 1268 - Trie - PythonEffective Coder · 21:40 · 191 views

The problem

You are 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 common prefix with searchWord. If there are more than three products with a common prefix return the three lexicographically minimums products.

Return a list of lists of the suggested products after each character of searchWord is typed.

Example 1:

Input: products = ["mobile","mouse","moneypot","monitor","mousepad"], searchWord = "mouse"
Output: [["mobile","moneypot","monitor"],["mobile","moneypot","monitor"],["mouse","mousepad"],["mouse","mousepad"],["mouse","mousepad"]]
Explanation: products sorted lexicographically = ["mobile","moneypot","monitor","mouse","mousepad"].
After typing m and mo all products match and we show user ["mobile","moneypot","monitor"].
After typing mou, mous and mouse the system suggests ["mouse","mousepad"].

Example 2:

Input: products = ["havana"], searchWord = "havana"
Output: [["havana"],["havana"],["havana"],["havana"],["havana"],["havana"]]
Explanation: The only word "havana" will be always suggested while typing the search word.

Constraints:

  • 1 <= products.length <= 1000
  • 1 <= products[i].length <= 3000
  • 1 <= sum(products[i].length) <= 2 * 104
  • All the strings of products are unique.
  • products[i] consists of lowercase English letters.
  • 1 <= searchWord.length <= 1000
  • searchWord consists of lowercase English letters.

Approach overview

Problem Overview: You are given a list of product names and a search word. As the user types each character of the search word, return up to three lexicographically smallest products that start with the current prefix.

Approach 1: Sorting and Linear Prefix Filtering (Time: O(n log n + m * n), Space: O(1) extra)

Start by sorting the product list lexicographically using sorting. For every prefix of the search word, iterate through the sorted list and collect the first three products that start with that prefix. Because the array is sorted, the first matches you encounter are already the smallest in lexicographical order. The key operation is repeated prefix comparison using string.startswith() or substring checks. This approach is easy to implement and works well when the product list is small, but scanning the full list for every prefix leads to O(m * n) checks where m is the search word length.

Approach 2: Trie Data Structure (Time: O(n * k + m * k), Space: O(n * k))

A more scalable solution uses a Trie to store product names character by character. Each node represents a prefix and stores up to three lexicographically smallest product suggestions that share that prefix. Insert every product into the Trie while maintaining a sorted list of at most three suggestions at each node. When processing the search word, traverse the Trie one character at a time and read the stored suggestions directly from the current node. This avoids scanning the entire product list repeatedly and turns the search process into simple prefix traversal.

The Trie approach leverages prefix sharing between strings, which is exactly what the problem models. It also aligns with typical autocomplete system design. Operations mainly involve character traversal and prefix lookup within the Trie, a common pattern in string and search problems.

Recommended for interviews: The Trie solution is usually what interviewers expect because it models a real-world autocomplete system and achieves predictable performance. The sorting approach still demonstrates good understanding of lexicographical ordering and prefix filtering, so it is a solid starting point during discussion before moving to the optimized Trie-based design.

Approach 1: Sorting and Linear Search Approach

This approach involves sorting the products array first and then iteratively constructing prefixes from the searchWord. For each prefix, use a simple linear search over the sorted products array to find matches. By keeping the products sorted, it ensures that we can easily pick the smallest lexicographical options.

After sorting, for every prefix of the searchWord, we traverse the sorted products list, check if the product starts with the current prefix, and collect up to three matches.

def suggestedProducts(products, searchWord):
    products.sort()
    result = []
    prefix = ''
    for char in searchWord:
        prefix += char
        matches = [product for product in products if product.startswith(prefix)]
        result.append(matches[:3])
    return result

# Example usage:
products = ["mobile","mouse","moneypot","monitor","mousepad"]
searchWord = "mouse"
print(suggestedProducts(products, searchWord))
import java.util.*;

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

    public static void main(String[] args) {
        String[] products = {"mobile","mouse","moneypot","monitor","mousepad"};
        String searchWord = "mouse";
        SearchSuggestions ss = new SearchSuggestions();
        System.out.println(ss.suggestedProducts(products, searchWord));
    }
}
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

vector<vector<string>> suggestedProducts(vector<string>& products, string searchWord) {
    sort(products.begin(), products.end());
    vector<vector<string>> result;
    string prefix;
    for (char c : searchWord) {
        prefix += c;
        vector<string> matches;
        for (string &product : products) {
            if (product.compare(0, prefix.size(), prefix) == 0) {
                matches.push_back(product);
                if (matches.size() == 3) break;
            }
        }
        result.push_back(matches);
    }
    return result;
}

int main() {
    vector<string> products = {"mobile","mouse","moneypot","monitor","mousepad"};
    string searchWord = "mouse";
    vector<vector<string>> result = suggestedProducts(products, searchWord);
    for (auto &list : result) {
        for (auto &prod : list) {
            cout << prod << " ";
        }
        cout << endl;
    }
    return 0;
}
function suggestedProducts(products, searchWord) {
    products.sort();
    let result = [];
    let prefix = '';
    for (let char of searchWord) {
        prefix += char;
        let matches = products.filter(product => product.startsWith(prefix)).slice(0, 3);
        result.push(matches);
    }
    return result;
}

// Example usage:
const products = ["mobile","mouse","moneypot","monitor","mousepad"];
const searchWord = "mouse";
console.log(suggestedProducts(products, searchWord));
using System;
using System.Collections.Generic;

class SearchSuggestions {
    public IList<IList<string>> SuggestedProducts(string[] products, string searchWord) {
        Array.Sort(products);
        List<IList<string>> result = new List<IList<string>>();
        string prefix = string.Empty;
        foreach (char c in searchWord) {
            prefix += c;
            List<string> matches = new List<string>();
            foreach (string product in products) {
                if (product.StartsWith(prefix)) {
                    matches.Add(product);
                    if (matches.Count == 3) break;
                }
            }
            result.Add(matches);
        }
        return result;
    }

    static void Main() {
        string[] products = {"mobile","mouse","moneypot","monitor","mousepad"};
        string searchWord = "mouse";
        SearchSuggestions ss = new SearchSuggestions();
        var result = ss.SuggestedProducts(products, searchWord);
        foreach (var list in result) {
            Console.WriteLine(string.Join(" ", list));
        }
    }
}

This Python code starts by sorting the list of products. As we iterate through each character of the searchWord, it builds the prefix and filters products that start with the current prefix. We then select the first three such products.

Complexity

Time Complexity: O(n log n) due to sorting, where n is the length of products. Each prefix search is O(n), leading to an overall complexity of O(n log n + m * n), where m is the length of searchWord.

Space Complexity: O(1) additional space is needed outside the result storage, although storing results may take O(m * 3) space.

Try this approach in the editor

Approach 2: Trie Data Structure Approach

This approach aims at using a Trie to efficiently handle prefix matching. With a Trie, we insert all product names into the Trie. As each character is typed in the searchWord, we traverse the Trie to check for the top three lexicographical matches.

Using a Trie allows us to handle the prefix matching efficiently by navigating through the structure step by step according to the current prefix.

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

class Solution:
    def insert(self, word, root):
        node = root
        for char in word:
            if char not in node.children:
                node.children[char] = TrieNode()
            node = node.children[char]
            if len(node.suggestions) < 3:
                node.suggestions.append(word)

    def suggestedProducts(self, products, searchWord):
        root = TrieNode()
        for product in sorted(products):
            self.insert(product, root)
        result, node = [], root
        for char in searchWord:
            if node:
                node = node.children.get(char)
            result.append(node.suggestions if node else [])
        return result

# Example usage:
products = ["mobile","mouse","moneypot","monitor","mousepad"]
searchWord = "mouse"
solution = Solution()
print(solution.suggestedProducts(products, searchWord))
import java.util.*;

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

class Solution {
    public void insert(String product, TrieNode node) {
        for (char c : product.toCharArray()) {
            node = node.children.computeIfAbsent(c, k -> new TrieNode());
            if (node.suggestions.size() < 3) {
                node.suggestions.add(product);
            }
        }
    }

    public List<List<String>> suggestedProducts(String[] products, String searchWord) {
        Arrays.sort(products);
        TrieNode root = new TrieNode();
        for (String product : products) {
            insert(product, root);
        }
        List<List<String>> result = new ArrayList<>();
        TrieNode node = root;
        for (char c : searchWord.toCharArray()) {
            node = node != null ? node.children.get(c) : null;
            result.add(node != null ? node.suggestions : new ArrayList<>());
        }
        return result;
    }

    public static void main(String[] args) {
        String[] products = {"mobile","mouse","moneypot","monitor","mousepad"};
        String searchWord = "mouse";
        Solution solution = new Solution();
        System.out.println(solution.suggestedProducts(products, searchWord));
    }
}
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;

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

class Solution {
public:
    void insert(string product, TrieNode* node) {
        for (char c : product) {
            if (!node->children.count(c)) {
                node->children[c] = new TrieNode();
            }
            node = node->children[c];
            if (node->suggestions.size() < 3) {
                node->suggestions.push_back(product);
            }
        }
    }

    vector<vector<string>> suggestedProducts(vector<string>& products, string searchWord) {
        sort(products.begin(), products.end());
        TrieNode* root = new TrieNode();
        for (string& product : products) {
            insert(product, root);
        }
        vector<vector<string>> result;
        TrieNode* node = root;
        for (char c : searchWord) {
            if (node) {
                node = node->children.count(c) ? node->children[c] : nullptr;
            }
            result.push_back(node ? node->suggestions : vector<string>());
        }
        return result;
    }
};

int main() {
    vector<string> products = {"mobile","mouse","moneypot","monitor","mousepad"};
    string searchWord = "mouse";
    Solution solution;
    vector<vector<string>> result = solution.suggestedProducts(products, searchWord);
    for (auto &list : result) {
        for (auto &prod : list) {
            cout << prod << " ";
        }
        cout << endl;
    }
    return 0;
}
class TrieNode {
    constructor() {
        this.children = {};
        this.suggestions = [];
    }
}

function insertProduct(product, root) {
    let node = root;
    for (let char of product) {
        if (!node.children[char]) {
            node.children[char] = new TrieNode();
        }
        node = node.children[char];
        if (node.suggestions.length < 3) {
            node.suggestions.push(product);
        }
    }
}

function suggestedProducts(products, searchWord) {
    products.sort();
    let root = new TrieNode();
    for (let product of products) {
        insertProduct(product, root);
    }
    let result = [];
    let node = root;
    for (let char of searchWord) {
        node = node ? node.children[char] : null;
        result.push(node ? node.suggestions : []);
    }
    return result;
}

// Example usage:
const products = ["mobile","mouse","moneypot","monitor","mousepad"];
const searchWord = "mouse";
console.log(suggestedProducts(products, searchWord));
using System;
using System.Collections.Generic;

class TrieNode {
    public Dictionary<char, TrieNode> Children = new Dictionary<char, TrieNode>();
    public List<string> Suggestions = new List<string>();
}

class Solution {
    public void Insert(string product, TrieNode node) {
        foreach (char c in product) {
            if (!node.Children.ContainsKey(c)) {
                node.Children[c] = new TrieNode();
            }
            node = node.Children[c];
            if (node.Suggestions.Count < 3) {
                node.Suggestions.Add(product);
            }
        }
    }

    public IList<IList<string>> SuggestedProducts(string[] products, string searchWord) {
        Array.Sort(products);
        TrieNode root = new TrieNode();
        foreach (string product in products) {
            Insert(product, root);
        }
        List<IList<string>> result = new List<IList<string>>();
        TrieNode node = root;
        foreach (char c in searchWord) {
            if (node != null) {
                node = node.Children.ContainsKey(c) ? node.Children[c] : null;
            }
            result.Add(node != null ? new List<string>(node.Suggestions) : new List<string>());
        }
        return result;
    }

    static void Main() {
        string[] products = {"mobile","mouse","moneypot","monitor","mousepad"};
        string searchWord = "mouse";
        Solution solution = new Solution();
        var result = solution.SuggestedProducts(products, searchWord);
        foreach (var list in result) {
            Console.WriteLine(string.Join(" ", list));
        }
    }
}

This Python code uses a Trie structure. We create nodes for each character and keep track of the top three suggestions within the TrieNode. As searchWord is typed, we navigate the Trie and retrieve suggestions.

Complexity

Time Complexity: O(n m) to insert all products (where n is number of products and m is max product length), and O(k) to search for each prefix (where k is the length of searchWord).

Space Complexity: O(n m) for the Trie storage, since we store each character of every word.

Try this approach in the editor

Approach 3: Sorting + Trie

The problem requires that after each letter of the input searchWord, recommend up to three products from the products array that have the same prefix as searchWord. If there are more than three products with the same prefix that can be recommended, return the three with the smallest lexicographic order.

To find products with the same prefix, we can use a trie; to return the three products with the smallest lexicographic order, we can first sort the products array, and then store the indices of the sorted array in the trie.

Each node of the trie maintains the following information:

  • children: This is an array of length 26, used to store the child nodes of the current node. children[i] represents the node whose character is i + 'a' among the child nodes of the current node.
  • v: This is an array, used to store the indices of the characters in the products array among the child nodes of the current node, storing up to three indices.

During the search, we start from the root node of the trie, find the index array corresponding to each prefix, and store it in the result array. Finally, we only need to map each index in the index array to the products array.

The time complexity is O(L times log n + m), and the space complexity is O(L). Where L is the sum of the lengths of all strings in the products array, and n and m are the lengths of the products array and searchWord, respectively.

type Trie struct {
	children [26]*Trie
	v        []int
}

func newTrie() *Trie {
	return &Trie{}
}
func (this *Trie) insert(w string, i int) {
	node := this
	for _, c := range w {
		c -= 'a'
		if node.children[c] == nil {
			node.children[c] = newTrie()
		}
		node = node.children[c]
		if len(node.v) < 3 {
			node.v = append(node.v, i)
		}
	}
}

func (this *Trie) search(w string) [][]int {
	node := this
	n := len(w)
	ans := make([][]int, n)
	for i, c := range w {
		c -= 'a'
		if node.children[c] == nil {
			break
		}
		node = node.children[c]
		ans[i] = node.v
	}
	return ans
}

func suggestedProducts(products []string, searchWord string) (ans [][]string) {
	sort.Strings(products)
	trie := newTrie()
	for i, w := range products {
		trie.insert(w, i)
	}
	for _, v := range trie.search(searchWord) {
		t := []string{}
		for _, i := range v {
			t = append(t, products[i])
		}
		ans = append(ans, t)
	}
	return
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Sorting and Linear Search Approach

Time Complexity: O(n log n) due to sorting, where n is the length of products. Each prefix search is O(n), leading to an overall complexity of O(n log n + m * n), where m is the length of searchWord.

Space Complexity: O(1) additional space is needed outside the result storage, although storing results may take O(m * 3) space.

Trie Data Structure Approach

Time Complexity: O(n m) to insert all products (where n is number of products and m is max product length), and O(k) to search for each prefix (where k is the length of searchWord).

Space Complexity: O(n m) for the Trie storage, since we store each character of every word.

Sorting + Trie–

Complexity analysis

ApproachTimeSpaceWhen to Use
Sorting and Linear Prefix FilteringO(n log n + m * n)O(1)Simple implementation when the product list is small or constraints are moderate
Trie Data StructureO(n * k + m * k)O(n * k)Best for large datasets or autocomplete-style systems requiring fast prefix lookups

Frequently asked questions

Is Search Suggestions System easy or hard?

Search Suggestions System is classified as a Medium problem on LeetCode. The core difficulty comes from recognizing that prefix-based queries benefit from a Trie rather than repeatedly scanning the entire product list.

Search Suggestions System Python/Java solution

Python, Java, C++, C#, and JavaScript implementations typically follow two patterns: sorting products and filtering by prefix, or building a Trie that stores up to three suggestions at each node. The Trie implementation is more efficient for large datasets.

How to solve Search Suggestions System in O(n)?

Strict O(n) is not achievable because product strings must be processed character by character. The closest optimal approach is building a Trie in O(n * k) time and then traversing it for each prefix of the search word in O(m * k). This avoids repeatedly scanning the entire product list.

What is the best approach for Search Suggestions System?

The Trie-based approach is generally considered the best solution. It stores product prefixes in a prefix tree and keeps up to three lexicographically smallest suggestions at each node. This allows quick lookup for each character typed in the search word, leading to O(n * k + m * k) time complexity where k is the average product length.

Is Search Suggestions System asked at Google/Amazon/Meta?

Autocomplete and prefix search problems appear frequently in interviews at companies like Google, Amazon, and Meta. Variants often test Trie implementation, efficient prefix search, and system design ideas used in search engines or e-commerce product suggestions.

What data structure is used in Search Suggestions System?

The primary data structure is a Trie (prefix tree), which efficiently stores strings by shared prefixes. Some simpler solutions rely on sorting arrays and performing prefix checks, sometimes combined with binary search to narrow the candidate range.

What is the time complexity of Search Suggestions System?

The optimal Trie solution runs in O(n * k + m * k) time, where n is the number of products, k is the average product length, and m is the search word length. A simpler sorting and scanning approach takes O(n log n + m * n) because it checks the product list for every prefix.

Comments

Now write it yourselfClose this page and solve Search Suggestions System in the editor, without looking.
Practise Search Suggestions System