Word Search in Trie in DSA Rust - Time & Space Complexity
We want to understand how long it takes to find a word in a Trie data structure.
The question is: how does the search time grow as the word length or Trie size changes?
Analyze the time complexity of the following code snippet.
struct TrieNode {
children: [Option; 26],
is_end: bool,
}
impl TrieNode {
fn search(&self, word: &str) -> bool {
let mut node = self;
for ch in word.chars() {
let idx = (ch as usize) - ('a' as usize);
match &node.children[idx] {
Some(child) => node = child.as_ref(),
None => return false,
}
}
node.is_end
}
}
This code searches for a word in a Trie by checking each character one by one.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Loop over each character in the input word.
- How many times: Exactly once per character in the word (word length).
As the word gets longer, the search checks more characters one after another.
| Input Size (n = word length) | Approx. Operations |
|---|---|
| 10 | About 10 character checks |
| 100 | About 100 character checks |
| 1000 | About 1000 character checks |
Pattern observation: The number of steps grows directly with the word length.
Time Complexity: O(n)
This means the search time grows linearly with the length of the word you want to find.
[X] Wrong: "Searching a word in a Trie depends on the total number of words stored."
[OK] Correct: The search only depends on the length of the word being searched, not how many words are in the Trie.
Knowing how Trie search scales helps you explain why Tries are efficient for prefix and word lookups.
This skill shows you understand how data structure design affects performance.
"What if we changed the search to allow wildcards that match any character? How would the time complexity change?"
Practice
Trie data structure in word search problems?Solution
Step 1: Understand Trie structure
A Trie stores characters in nodes where each path from root to a node represents a prefix of words.Step 2: Purpose in word search
This structure allows quick prefix checks and word searches, making it efficient for word search problems.Final Answer:
To efficiently store and search words by their prefixes -> Option CQuick Check:
Trie = Prefix search [OK]
- Confusing Trie with hash tables
- Thinking Trie sorts words
- Assuming Trie stores whole words only
Solution
Step 1: Understand Rust ownership and pointers
To allow recursive data structures, Rust uses Box to allocate on heap and Option for nullable children.Step 2: Correct syntax for children field
Children should be a vector of optional boxed TrieNode references: Vec>.Final Answer:
struct TrieNode { children: Vec> } -> Option AQuick Check:
Recursive struct uses Box and Option [OK]
- Using Vec<TrieNode> causes infinite size error
- Wrapping Vec in Option instead of elements
- Incorrect Box placement
struct TrieNode {
children: Vec>,
is_end: bool,
}
impl TrieNode {
fn search(&self, word: &str) -> bool {
let mut node = self;
for ch in word.chars() {
let index = (ch as usize) - ('a' as usize);
match &node.children[index] {
Some(child) => node = child,
None => return false,
}
}
node.is_end
}
}
fn main() {
let mut root = TrieNode {
children: vec![None; 26],
is_end: false,
};
println!("{}", root.search("cat"));
println!("{}", root.search("car"));
}Solution
Step 1: Analyze search function behavior
The search returns true if all characters are found and the last node marks end of a word.Step 2: Check given calls
No words are inserted; root.children initialized to vec![None; 26]. For "cat" and "car", first char 'c' (index 2) is None, so both return false.Final Answer:
false false -> Option BQuick Check:
Search returns false for non-inserted words [OK]
- Assuming partial prefix returns true
- Ignoring is_end flag
- Confusing character indexing
fn search(&self, word: &str) -> bool {
let mut node = self;
for ch in word.chars() {
let index = (ch as usize) - ('a' as usize);
if node.children[index].is_some() {
node = &node.children[index].unwrap();
} else {
return false;
}
}
true
}Solution
Step 1: Understand search logic
The method should return true only if the word ends at a node marked as end of a word.Step 2: Identify bug in return statement
Returning true always ignores if the node marks end of a word; must return node.is_end.Final Answer:
Return node.is_end instead of true at the end -> Option AQuick Check:
Search must check is_end flag [OK]
- Returning true without checking is_end
- Ignoring None cases
- Misusing unwrap without safety
Solution
Step 1: Traverse Trie for prefix
Follow nodes for each character in prefix to reach prefix node.Step 2: Collect words recursively
From prefix node, recursively explore children to collect all complete words.Final Answer:
Traverse Trie nodes for prefix, then recursively collect all words from that node -> Option DQuick Check:
Prefix traversal + recursive collection = A [OK]
- Checking all words instead of prefix traversal
- Using external data structures unnecessarily
- Ignoring recursive collection after prefix
Ready to prove it?
Pass the test and this pattern moves unknown
