Why Trie Exists and What Hash Map Cannot Do for Strings
📖 Scenario: Imagine you are building a search feature for a phone contacts app. You want to quickly find all contacts whose names start with certain letters typed by the user.Using a hash map (dictionary) can find exact names fast, but it cannot efficiently find all names starting with a prefix. This is where a Trie (prefix tree) helps.
🎯 Goal: Build a simple Trie data structure to store contact names and find all names starting with a given prefix.This will show why a Trie is useful and what a hash map cannot do easily for strings.
📋 What You'll Learn
Create a Trie node class with children and end-of-word marker
Insert given contact names into the Trie
Search the Trie for all names starting with a given prefix
Print the list of names found with the prefix
💡 Why This Matters
🌍 Real World
Tries are used in search engines, autocomplete features, and spell checkers to quickly find words starting with typed letters.
💼 Career
Understanding Tries helps in roles involving text processing, search optimization, and building efficient string-based data structures.
Progress0 / 4 steps
1
Create Trie Node Class and Insert Contacts
Create a class called TrieNode with an attribute children as an empty dictionary and is_end_of_word as False. Then create a class called Trie with a root node of type TrieNode. Add a method insert in Trie that takes a string word and inserts it character by character into the Trie, marking the end of the word.
DSA Python
Hint
Think of each TrieNode as a box holding letters leading to next letters. Insert each letter step by step.
2
Add a Prefix Search Helper Method
Add a method called _search_node in the Trie class that takes a string prefix and returns the node where the prefix ends or None if prefix not found.
DSA Python
Hint
Follow each letter of prefix down the Trie. If any letter missing, return None.
3
Find All Words Starting with a Prefix
Add a method called starts_with in the Trie class that takes a string prefix and returns a list of all words in the Trie that start with that prefix. Use the _search_node method to find the node for the prefix, then recursively collect all words below it.
DSA Python
Hint
Use depth-first search from the prefix node to find all complete words.
4
Print All Contacts Starting with a Given Prefix
Use the starts_with method of the trie object to find all contact names starting with the prefix "al". Print the resulting list.
DSA Python
Hint
Call print(trie.starts_with("al")) to see all names starting with 'al'.
Practice
(1/5)
1. Why do we use a Trie data structure instead of a Hash Map for storing a large set of strings?
easy
A. Because Trie uses less memory than Hash Map always
B. Because Trie supports efficient prefix search which Hash Map cannot do easily
C. Because Hash Map cannot store strings as keys
D. Because Trie is faster for all types of lookups
Solution
Step 1: Understand Trie and Hash Map capabilities
Trie stores strings in a tree form allowing prefix-based queries efficiently. Hash Map stores keys but does not support prefix search directly.
Step 2: Compare prefix search ability
Hash Map can check full keys but cannot find all keys with a given prefix efficiently. Trie can find all keys sharing a prefix quickly.
Final Answer:
Because Trie supports efficient prefix search which Hash Map cannot do easily -> Option B
Quick Check:
Prefix search = Trie advantage [OK]
Hint: Trie is for prefix search; Hash Map is not [OK]
Common Mistakes:
Thinking Hash Map can do prefix search efficiently
Assuming Trie always uses less memory
Believing Hash Map cannot store string keys
2. Which of the following is the correct way to initialize a Trie node in Python?
easy
A. node = set()
B. node = []
C. node = {'children': {}, 'is_end': False}
D. node = ''
Solution
Step 1: Identify Trie node structure
A Trie node typically has a dictionary for children and a boolean to mark end of word.
Step 2: Match with options
node = {'children': {}, 'is_end': False} correctly uses a dictionary for children and a boolean flag. Others do not represent Trie node structure.
Final Answer:
node = {'children': {}, 'is_end': False} -> Option C
Quick Check:
Trie node = dict + bool [OK]
Hint: Trie node needs children dict and end flag [OK]
Common Mistakes:
Using list or set instead of dictionary for children
Not including end-of-word marker
Using empty string as node
3. What will be the output of the following code snippet?
class TrieNode:
def __init__(self):
self.children = {}
self.is_end = False
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word):
node = self.root
for char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.is_end = True
def search(self, word):
node = self.root
for char in word:
if char not in node.children:
return False
node = node.children[char]
return node.is_end
trie = Trie()
trie.insert('cat')
trie.insert('car')
print(trie.search('cat'))
print(trie.search('ca'))
print(trie.search('car'))
medium
A. True\nFalse\nTrue
B. True\nTrue\nTrue
C. False\nFalse\nFalse
D. True\nFalse\nFalse
Solution
Step 1: Insert words 'cat' and 'car'
Both words are inserted character by character, marking end of word at last character.
Step 2: Search for 'cat', 'ca', and 'car'
'cat' and 'car' exist fully with end marked True, so search returns True. 'ca' is prefix but not end of word, so returns False.
Final Answer:
True\nFalse\nTrue -> Option A
Quick Check:
Search full word only returns true [OK]
Hint: Search returns true only if full word inserted [OK]
Common Mistakes:
Assuming prefix search returns true
Confusing is_end flag usage
Not updating node during insert
4. The following code tries to insert words into a Trie but has a bug. What is the bug?
class TrieNode:
def __init__(self):
self.children = {}
self.is_end = False
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word):
node = self.root
for char in word:
if char in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.is_end = True
medium
A. It does not initialize the root node
B. It never marks the end of word
C. It uses list instead of dictionary for children
D. It overwrites existing child nodes instead of checking if they exist
Solution
Step 1: Analyze insert method condition
The code checks if char is in children, then overwrites with new TrieNode, which erases existing nodes.
Step 2: Identify correct logic
It should add new TrieNode only if char NOT in children, to avoid overwriting existing nodes.
Final Answer:
It overwrites existing child nodes instead of checking if they exist -> Option D
Quick Check:
Insert overwrites nodes = bug [OK]
Hint: Add node only if child missing, not if present [OK]
Common Mistakes:
Confusing if condition logic
Forgetting to mark end of word
Not initializing root node
5. You want to find all words in a dictionary that start with the prefix 'pre'. Why is a Trie better than a Hash Map for this task, and how would you implement the prefix search?
hard
A. Trie stores words in a tree allowing prefix traversal; implement by walking nodes for prefix then collecting all descendants
B. Hash Map stores keys with prefix indexing; implement by filtering keys starting with prefix
C. Trie hashes prefixes for quick lookup; implement by hashing prefix and returning matches
D. Hash Map stores words sorted; implement by binary search on keys
Solution
Step 1: Understand prefix search in Trie vs Hash Map
Trie organizes words by characters in a tree, enabling direct traversal to prefix node. Hash Map keys are unordered, so prefix search requires scanning all keys.
Step 2: Describe prefix search implementation in Trie
Traverse Trie nodes for each prefix character, then recursively collect all words from that node's descendants.
Final Answer:
Trie stores words in a tree allowing prefix traversal; implement by walking nodes for prefix then collecting all descendants -> Option A