Why Trie Exists and What Hash Map Cannot Do for Strings
📖 Scenario: Imagine you are building a search feature for a phone book app. You want to quickly find all contacts whose names start with certain letters. Using a hash map works well for exact names but struggles when you want to find names by prefixes.
🎯 Goal: Build a simple prefix search using a Trie data structure to find all names starting with a given prefix. Understand why a Trie is better than a hash map for prefix queries.
📋 What You'll Learn
Create an array called contacts with these exact names: 'alice', 'alex', 'bob', 'bobby', 'carol'
Create a variable called prefix and set it to the string 'bo'
Implement a simple Trie class with insert and startsWith methods
Use the Trie to find all contacts starting with prefix
Print the list of matching contacts
💡 Why This Matters
🌍 Real World
Tries are used in autocomplete features, spell checkers, and IP routing where prefix matching is needed.
💼 Career
Understanding Tries helps in roles involving search engines, text processing, and efficient data retrieval.
Progress0 / 4 steps
1
Create the contacts list
Create an array called contacts with these exact strings: 'alice', 'alex', 'bob', 'bobby', 'carol'
DSA Typescript
Hint
Use const contacts = ['alice', 'alex', 'bob', 'bobby', 'carol'];
2
Set the prefix to search
Create a variable called prefix and set it to the string 'bo'
DSA Typescript
Hint
Use const prefix = 'bo';
3
Implement the Trie class with insert and startsWith
Create a class called Trie with methods insert(word: string): void and startsWith(prefix: string): string[]. The insert method adds a word to the Trie. The startsWith method returns all words in the Trie that start with the given prefix.
DSA Typescript
Hint
Define a Trie class with insert and startsWith methods. Use a Map to store children nodes.
4
Find and print contacts starting with the prefix
Use the startsWith method of the trie object to find all contacts starting with prefix. Print the resulting array.
DSA Typescript
Hint
Call trie.startsWith(prefix) and print the result using console.log.
Practice
(1/5)
1. Why do we use a Trie data structure instead of a Hash Map for storing many strings?
easy
A. Because Trie is faster for exact string lookups than Hash Maps
B. Because Trie uses less memory than a Hash Map for all cases
C. Because Hash Maps cannot store strings as keys
D. Because Trie efficiently supports prefix-based searches and auto-completion
Solution
Step 1: Understand Trie and Hash Map capabilities
Trie stores strings in a tree form, allowing quick prefix searches. Hash Maps store keys but do not support prefix queries efficiently.
Step 2: Compare use cases for prefix search
Trie can find all strings starting with a prefix quickly, which Hash Maps cannot do without scanning all keys.
Final Answer:
Because Trie efficiently supports prefix-based searches and auto-completion -> Option D
Thinking Hash Maps support prefix search efficiently
Assuming Trie always uses less memory
Believing Hash Maps cannot store strings as keys
2. Which of the following is the correct TypeScript syntax to declare a Trie node with children as a Map of characters to nodes?
easy
A. class TrieNode { children: Map = new Map(); }
B. class TrieNode { children: Map = new Map(); }
C. class TrieNode { children: Map = new Map(); }
D. class TrieNode { children: Map = new Map(); }
Solution
Step 1: Understand Map type declaration in TypeScript
Map keys and values must be typed as Map. Here keys are characters (string), values are TrieNode.
Step 2: Check each option's syntax
class TrieNode { children: Map = new Map(); } correctly declares children as Map initialized with new Map(). Others have wrong generic order or types.
Final Answer:
class TrieNode { children: Map = new Map(); } -> Option A
Quick Check:
Map syntax correct [OK]
Hint: Map with correct order and initialization [OK]
Common Mistakes:
Swapping key and value types in Map
Not initializing Map with new Map()
Using wrong generic types for Map
3. Given the following TypeScript Trie insertion code snippet, what will be the output after inserting words ['cat', 'car', 'dog'] and searching for prefix 'ca'?
class TrieNode {
children: Map = new Map();
isEnd: boolean = false;
}
class Trie {
root = new TrieNode();
insert(word: string) {
let node = this.root;
for (const ch of word) {
if (!node.children.has(ch)) {
node.children.set(ch, new TrieNode());
}
node = node.children.get(ch)!;
}
node.isEnd = true;
}
startsWith(prefix: string): boolean {
let node = this.root;
for (const ch of prefix) {
if (!node.children.has(ch)) return false;
node = node.children.get(ch)!;
}
return true;
}
}
const trie = new Trie();
['cat', 'car', 'dog'].forEach(w => trie.insert(w));
console.log(trie.startsWith('ca'));
medium
A. undefined
B. true
C. false
D. Error at runtime
Solution
Step 1: Insert words into Trie
Words 'cat', 'car', and 'dog' are inserted. 'ca' prefix nodes are created for 'c' and 'a'.
Step 2: Check startsWith for 'ca'
Traversal finds nodes for 'c' and 'a' successfully, so returns true.
Final Answer:
true -> Option B
Quick Check:
Prefix 'ca' exists = true [OK]
Hint: If prefix nodes exist, startsWith returns true [OK]
Common Mistakes:
Confusing startsWith with exact word search
Assuming isEnd must be true for prefix check
Expecting false if prefix is partial
4. The following TypeScript Trie search method is intended to check if a word exists. What is the bug?
search(word: string): boolean {
let node = this.root;
for (const ch of word) {
if (!node.children.has(ch)) return false;
node = node.children.get(ch)!;
}
return false;
}
medium
A. It always returns false even if word exists
B. It throws an error when word is empty
C. It returns true for any prefix, not full word
D. It does not check if node is null
Solution
Step 1: Analyze the return statement after loop
The method returns false after the loop without checking if the last node marks end of a word.
Step 2: Identify missing isEnd check
It should return node.isEnd to confirm full word presence, not just prefix.
Final Answer:
It always returns false even if word exists -> Option A
Quick Check:
Missing isEnd check causes always false [OK]
Hint: Check isEnd after traversal to confirm full word [OK]
Common Mistakes:
Returning false without checking isEnd
Confusing prefix search with full word search
Ignoring empty string edge case
5. You want to store a large dictionary of words and quickly find all words starting with a given prefix. Why is a Trie better than a Hash Map for this, and what is a limitation of Hash Map in this scenario?
hard
A. Trie uses less memory than Hash Map; Hash Map cannot store string keys longer than 10 characters.
B. Trie supports exact word search only; Hash Map supports prefix search but slower.
C. Trie stores words in a prefix tree allowing fast prefix queries; Hash Map can't efficiently find keys by prefix without scanning all keys.
D. Trie is slower for insertion; Hash Map is faster for prefix search.
Solution
Step 1: Understand Trie prefix storage
Trie organizes words by shared prefixes in a tree, enabling quick retrieval of all words with a prefix.
Step 2: Understand Hash Map limitations
Hash Map stores keys without order, so prefix search requires checking all keys, which is inefficient.
Final Answer:
Trie stores words in a prefix tree allowing fast prefix queries; Hash Map can't efficiently find keys by prefix without scanning all keys. -> Option C
Quick Check:
Prefix search efficiency = Trie advantage [OK]
Hint: Trie = fast prefix search; Hash Map = no prefix search [OK]