Trie Insert Operation in DSA Rust - Time & Space Complexity
We want to understand how long it takes to add a word into a trie data structure.
Specifically, how the time grows as the word gets longer.
Analyze the time complexity of the following code snippet.
struct TrieNode {
children: [Option<Box<TrieNode>>; 26],
is_end_of_word: bool,
}
impl TrieNode {
fn new() -> Self {
TrieNode {
children: [None; 26],
is_end_of_word: false,
}
}
fn insert(&mut self, word: &str) {
let mut node = self;
for ch in word.chars() {
let index = (ch as usize) - ('a' as usize);
if node.children[index].is_none() {
node.children[index] = Some(Box::new(TrieNode::new()));
}
node = node.children[index].as_mut().unwrap();
}
node.is_end_of_word = true;
}
}
This code inserts a word into a trie by creating nodes for each character if needed.
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).
Each character in the word causes one step of work to check or create a node.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 steps |
| 100 | About 100 steps |
| 1000 | About 1000 steps |
Pattern observation: The work grows directly with the length of the word.
Time Complexity: O(n)
This means the time to insert grows linearly with the word length.
[X] Wrong: "Inserting a word takes time based on the number of words already in the trie."
[OK] Correct: The insert time depends only on the word length, not how many words are stored.
Understanding trie insert time helps you explain efficient prefix-based searches and dictionary operations.
"What if we changed the trie to store Unicode characters instead of only lowercase letters? How would the time complexity change?"
Practice
insert operation in a Trie data structure?Solution
Step 1: Understand the insert operation
The insert operation adds a new word by creating nodes for each character if they don't exist.Step 2: Compare with other operations
Deleting removes words, searching finds words, counting totals words. Insert specifically adds words.Final Answer:
To add a new word by creating nodes for each character -> Option CQuick Check:
Insert = Add word nodes [OK]
- Confusing insert with search or delete
- Thinking insert counts words
- Assuming insert modifies existing words
insert?Solution
Step 1: Recall Rust method call syntax
In Rust, methods are called with dot notation and parentheses for arguments, likeobject.method(args).Step 2: Check each option
trie.insert("word"); uses correct dot and parentheses syntax. trie.insert[word]; uses brackets incorrectly. insert.trie("word"); reverses object and method. trie->insert("word"); uses arrow syntax not used in Rust.Final Answer:
trie.insert("word"); -> Option BQuick Check:
Rust method call = dot + parentheses [OK]
- Using brackets instead of parentheses
- Reversing method and object order
- Using arrow syntax like C++
let mut trie = Trie::new();
trie.insert("cat");
trie.insert("car");
println!("{}", trie.search("car"));
println!("{}", trie.search("cap"));Solution
Step 1: Insert words "cat" and "car" into the Trie
Both words share prefix "ca" but differ at last character. Both get inserted fully.Step 2: Search for "car" and "cap"
"car" was inserted, so search returns true. "cap" was not inserted, so search returns false.Final Answer:
true\nfalse -> Option AQuick Check:
Inserted word found = true, missing word = false [OK]
- Assuming partial prefix means word exists
- Confusing search return values
- Thinking insert overwrites words
struct TrieNode {
children: HashMap,
is_end: bool,
}
impl TrieNode {
fn insert(&mut self, word: &str) {
let mut node = self;
for ch in word.chars() {
if !node.children.contains_key(&ch) {
node.children.insert(ch, TrieNode { children: HashMap::new(), is_end: false });
}
node = node.children.get_mut(&ch).unwrap();
}
node.is_end = true;
}
}Solution
Step 1: Understand recursive struct size problem
HashMap inside TrieNode causes infinite size because TrieNode contains itself directly.Step 2: Correct approach using Box or Rc
To fix, children should store Box<TrieNode> or Rc<TrieNode> to have a pointer and known size.Final Answer:
HashMap cannot store TrieNode directly due to recursive type size -> Option DQuick Check:
Recursive struct needs indirection like Box [OK]
- Ignoring recursive type size error
- Thinking get_mut() causes error
- Misplacing is_end assignment
Solution
Step 1: Understand prefix search requirement
To find all words with a prefix, the Trie must quickly identify nodes representing that prefix.Step 2: Use counts to optimize prefix queries
Storing counts of words passing through nodes during insert helps quickly know how many words share that prefix.Final Answer:
Store a count of words passing through each node during insert -> Option AQuick Check:
Prefix search needs counts at nodes [OK]
- Marking is_end only at root loses word ends
- Inserting words reversed breaks normal prefix logic
- Using vector loses fast char lookup
Ready to prove it?
Pass the test and this pattern moves unknown
