🧠
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
- Sort the products lexicographically.
- For each prefix of searchWord:
- Use binary search to find the leftmost product that matches or could match the prefix.
- 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.
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
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.