Recommended resources
The freely available resources this lesson will direct you to.
Hello! In our previous lessons, we dove deep into the backtracking paradigm, learning how to construct solutions and, just as importantly, how to analyze their performance. We saw how the recursion tree's size and shape determine the complexity for problems like subsets, permutations, and combinations.
Today, we pivot to a new topic and a fascinating data structure: the Trie, also known as a prefix tree. This lesson will introduce you to its fundamental structure and, critically, help you explain when it is preferable to a hash map for storing strings. This is a classic interview question that tests your ability to choose the right tool for the job. While seemingly different from backtracking, we will soon see how a trie can be used to dramatically optimize certain backtracking searches.
What is a Trie?
A Trie (pronounced "try") is a specialized tree-based data structure used for storing and retrieving a dynamic set of strings. Its name comes from "re-trie-val," highlighting its efficiency in search operations.
The key idea behind a trie is that it stores strings by sharing common prefixes. For example, if you store the words "stock", "stop", and "stalk", you don't store the "st" prefix three separate times. Instead, you create a path s -> t in the tree, and then branch off from the 't' node to complete the different words.
This structure is what makes a trie a "prefix tree". Let's explore its components.
Implement Trie (Prefix Tree) - Leetcode 208
The NeetCode video on implementing a Trie provides an excellent visual introduction. It walks through the core concept and how a word is actually placed into the structure.
Watch the initial overview from the beginning to understand the applications and purpose. Then, pay close attention to the segment from here, where the presenter demonstrates how the word "apple" is inserted node by node. Notice two key details: each character becomes a node, and a special marker is needed to signify the end of a word.
As you saw in the video, a trie consists of nodes where:
- Each node represents a single character.
- Each node has a set of children, which can be stored in various ways (we'll touch on this later). A common approach for the English alphabet is an array of 26 pointers.
- Each node often contains a boolean flag, typically called
isEndOfWord, to indicate that the path from the root to this node spells out a complete word in the set.
The image below illustrates this node structure. The root is an empty node, and from there, each character forms a link in a chain.

The isEndOfWord flag is crucial. Consider storing "car" and "carpet". Without this flag, traversing to the 'r' in "car" wouldn't tell you if "car" is a valid word itself or just a prefix of another word.
Trie Data Structure - Interview Cake
This article from Interview Cake offers another clear explanation of the trie's structure and the importance of marking word endings.
Read the initial section Quick reference for a concise definition. Then, focus on the section Marking word endings. This part explains perfectly why we need a way to distinguish between a prefix and a complete word, using "Maria" and "Mariana" as an example.
Trie vs. Hash Map: When to Use Which?
With your experience solving LeetCode problems, you know that the hash map (or hash set) is the default choice for O(1) average time lookups. If the problem is "Given a list of words, check if 'stock' is in the list," a hash set is extremely efficient.
A trie also offers efficient lookups. Searching for a word of length takes time because you traverse one level for each character. A hash map lookup also technically takes time because the hash function must process all characters. So, if their lookup times are comparable, why choose one over the other?
The decision hinges on the type of queries you need to perform.
The Deciding Factor: Prefix Queries
A trie's primary advantage is its ability to perform prefix-based queries efficiently. Operations like "find all words starting with 'sto'" or "does any word start with 'fin'?" are what tries are built for.
- With a Trie: To check if any word starts with "sto", you simply traverse the path
s -> t -> o. If this path exists, you know at least one word starts with that prefix. The time complexity is , where is the length of the prefix. - With a Hash Map: There is no efficient way to do this. You would have to iterate through every single word in your set, check if it starts with the prefix "sto", and then report the result. If you have a million words, this is incredibly slow.
Implement Trie (Prefix Tree) - Leetcode 208
Let's return to the NeetCode video, which makes this exact point.
Watch the segment from this timestamp, where the presenter explicitly states that the startsWith function is the main reason to use a trie over a hash map. Then, continue from the next section for a concrete example comparing the efficiency of a startsWith('b') query on a list of a million words versus on a trie.
This efficiency with prefixes is why tries are the foundation for features like autocomplete and typeahead search suggestions.
A Deeper Comparison
Let's break down the trade-offs further.
| Feature | Trie | Hash Map |
|---|---|---|
| Primary Use Case | Prefix-based searches (e.g., autocomplete, startsWith), longest prefix matching. |
Exact-match lookups (e.g., contains, search). |
| Search Time | where is the key length. Predictable worst-case time. | Average to hash, often simplified to . Worst-case depends on collision strategy. |
| Space Complexity | Can be high. Each node may store many pointers (e.g., 26 for an alphabet), many of which are null. | Generally more space-efficient, as it only stores the strings themselves plus some overhead. |
| Ordered Traversal | Yes. A simple pre-order traversal of the trie can retrieve all strings in alphabetical order. | No. Hash maps are inherently unordered. |
| Longest Prefix Match | Excellent. Natively supports finding the longest stored prefix of a given string (e.g., IP routing). | Inefficient. Requires complex logic or iterating through all possible prefixes of the query string. |
The following resources provide a great summary of this comparison.
This GeeksforGeeks article provides a structured breakdown of the advantages and disadvantages of each data structure.
Skim the definitions of Hash Table and Trie. Then, focus on the sections Advantages of Trie and Disadvantages of Trie. Finally, read the direct comparison under the heading Compare the Lookup operation. This reading reinforces the key trade-offs we've discussed.
The image below gives a high-level visual summary and shows a real-world application of longest-prefix matching in API routing, which is conceptually similar to how internet routers use tries to route traffic based on IP addresses.

A Note on Node Implementation
For a CS major, it's interesting to consider how the children of a trie node are stored. This choice has direct performance implications.
Trie data structure - Inside code
This video delves into the practical implementation choices for a trie node, discussing the time and space trade-offs.
Watch the segment from this timestamp. The presenter discusses four different ways to implement the children pointers in a node: Fixed-size array: Fast access (O(1)), but potentially wasteful in space. Hash table: More space-efficient if the character set is large and sparse, but with slightly more overhead than an array. Dynamic array/List: Space-efficient but requires a linear scan to find a child. Linked list of siblings: Very space-efficient, but finding a child can be slow. Understanding these options is key to designing a trie that is optimized for a specific problem's constraints.
Conclusion
In this lesson, we introduced the trie, a powerful data structure for handling string data. We focused on its structure and the critical factors that determine when to use it over a standard hash map.
Key Takeaways:
- A Trie is a tree-like data structure that stores strings by sharing common prefixes. Its nodes represent characters, and paths from the root represent strings. An
isEndOfWordflag is essential to distinguish complete words from prefixes. - The primary reason to choose a Trie over a Hash Map is for efficient prefix-based operations. If your application requires
startsWithqueries, autocomplete functionality, or longest-prefix matching, a trie is almost always the superior choice. - For simple, exact-match lookups, a Hash Map is typically preferred due to its O(1) average time complexity and generally lower memory footprint.
- There is a trade-off between space and time. Tries offer predictable performance for lookups but can be memory-intensive. Hash maps are often more space-efficient but have a non-deterministic worst-case time complexity due to hash collisions.
Now that we have a solid conceptual understanding of what a trie is and when to use it, our next step is to bring it to life.
In the next lesson, we will roll up our sleeves and implement the core insert, search, and startsWith operations for a standard trie. This will solidify your understanding and prepare you to solve a wide range of string-related interview problems.