Problem Description
A trie (pronounced as "try") or prefix tree is a tree data structure used to efficiently store and retrieve keys in a dataset of strings. There are various applications of this data structure, such as autocomplete and spellchecker.
Implement the Trie class:
Trie()Initializes the trie object.void insert(String word)Inserts the stringwordinto the trie.boolean search(String word)Returnstrueif the stringwordis in the trie (i.e., was inserted before), andfalseotherwise.boolean startsWith(String prefix)Returnstrueif there is a previously inserted stringwordthat has the prefixprefix, andfalseotherwise.
Examples
Input
["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
[[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
Output
[null, null, true, false, true, null, true]
Explanation
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // return True
trie.search("app"); // return False
trie.startsWith("app"); // return True
trie.insert("app");
trie.search("app"); // return True
Python Solution
class TrieNode:
def __init__(self):
self.children = {}
self.is_end = False
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word: str) -> None:
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: str) -> bool:
node = self.root
for char in word:
if char not in node.children:
return False
node = node.children[char]
return node.is_end
def startsWith(self, prefix: str) -> bool:
node = self.root
for char in prefix:
if char not in node.children:
return False
node = node.children[char]
return True
Java Solution
class TrieNode {
private TrieNode[] children;
private boolean isEnd;
public TrieNode() {
children = new TrieNode[26];
isEnd = false;
}
}
class Trie {
private TrieNode root;
public Trie() {
root = new TrieNode();
}
public void insert(String word) {
TrieNode node = root;
for (char c : word.toCharArray()) {
int index = c - 'a';
if (node.children[index] == null) {
node.children[index] = new TrieNode();
}
node = node.children[index];
}
node.isEnd = true;
}
public boolean search(String word) {
TrieNode node = root;
for (char c : word.toCharArray()) {
int index = c - 'a';
if (node.children[index] == null) {
return false;
}
node = node.children[index];
}
return node.isEnd;
}
public boolean startsWith(String prefix) {
TrieNode node = root;
for (char c : prefix.toCharArray()) {
int index = c - 'a';
if (node.children[index] == null) {
return false;
}
node = node.children[index];
}
return true;
}
}
C++ Solution
class TrieNode {
public:
array children;
bool isEnd;
TrieNode() {
children.fill(nullptr);
isEnd = false;
}
~TrieNode() {
for (auto child : children) {
delete child;
}
}
};
class Trie {
private:
TrieNode* root;
public:
Trie() {
root = new TrieNode();
}
~Trie() {
delete root;
}
void insert(string word) {
TrieNode* node = root;
for (char c : word) {
int index = c - 'a';
if (!node->children[index]) {
node->children[index] = new TrieNode();
}
node = node->children[index];
}
node->isEnd = true;
}
bool search(string word) {
TrieNode* node = root;
for (char c : word) {
int index = c - 'a';
if (!node->children[index]) {
return false;
}
node = node->children[index];
}
return node->isEnd;
}
bool startsWith(string prefix) {
TrieNode* node = root;
for (char c : prefix) {
int index = c - 'a';
if (!node->children[index]) {
return false;
}
node = node->children[index];
}
return true;
}
};
JavaScript Solution
class TrieNode {
constructor() {
this.children = {};
this.isEnd = false;
}
}
class Trie {
constructor() {
this.root = new TrieNode();
}
insert(word) {
let node = this.root;
for (const char of word) {
if (!(char in node.children)) {
node.children[char] = new TrieNode();
}
node = node.children[char];
}
node.isEnd = true;
}
search(word) {
let node = this.root;
for (const char of word) {
if (!(char in node.children)) {
return false;
}
node = node.children[char];
}
return node.isEnd;
}
startsWith(prefix) {
let node = this.root;
for (const char of prefix) {
if (!(char in node.children)) {
return false;
}
node = node.children[char];
}
return true;
}
}
C# Solution
public class TrieNode {
public TrieNode[] children;
public bool isEnd;
public TrieNode() {
children = new TrieNode[26];
isEnd = false;
}
}
public class Trie {
private TrieNode root;
public Trie() {
root = new TrieNode();
}
public void Insert(string word) {
TrieNode node = root;
foreach (char c in word) {
int index = c - 'a';
if (node.children[index] == null) {
node.children[index] = new TrieNode();
}
node = node.children[index];
}
node.isEnd = true;
}
public bool Search(string word) {
TrieNode node = root;
foreach (char c in word) {
int index = c - 'a';
if (node.children[index] == null) {
return false;
}
node = node.children[index];
}
return node.isEnd;
}
public bool StartsWith(string prefix) {
TrieNode node = root;
foreach (char c in prefix) {
int index = c - 'a';
if (node.children[index] == null) {
return false;
}
node = node.children[index];
}
return true;
}
}
Complexity Analysis
- Time Complexity:
- Insert: O(m) where m is the length of the word
- Search: O(m) where m is the length of the word
- StartsWith: O(m) where m is the length of the prefix
- Space Complexity: O(ALPHABET_SIZE × N × M) where N is the number of words and M is the average length of words
Solution Explanation
The Trie data structure is implemented using the following components:
- TrieNode:
- Children nodes (array or map)
- End of word marker
- Optional character value
- Operations:
- Insert: Add word character by character
- Search: Find exact word match
- StartsWith: Find prefix match
Implementation Choices
- Array vs HashMap:
- Array: Fixed size, faster access
- HashMap: Dynamic size, more flexible
- Trade-off between space and time
- Memory Management:
- Proper cleanup in C++
- Garbage collection in other languages
- Memory efficiency considerations
Common Applications
- Autocomplete
- Spell checker
- IP routing tables
- Dictionary implementation
Optimization Tips
- Case sensitivity handling
- Memory pooling
- Path compression
- Deletion support