DSA Guide
Tries

Tries

A tree keyed by character, where shared prefixes are stored once — and the one question a hash map cannot answer

A trie (said "try", from retrieval) is a tree where each edge is a character and each path from the root spells a prefix.

It exists to answer one question a hash map cannot: "which stored words start with this?"

What a Trie Looks Like

Storing "cat", "car", "card" and "dog":

            (root)
            /    \
           c      d
           |      |
           a      o
          / \     |
         t   r    g •          • marks the end of a word
         •   •    \
             |
             d •

The words "cat", "car" and "card" all share the path c → a. That prefix is stored once, not three times.

The vocabulary

TermMeans
NodeOne position in the tree. Holds children and an end-of-word flag.
EdgeA single character leading to a child node.
ChildrenA map from character → next node. Often a dict, sometimes a 26-slot array.
End-of-word flag"A complete word finishes here." Without it you cannot tell "car" from the prefix of "card".
PrefixAny path from the root. Every node is a prefix.

The root represents the empty string and holds no character of its own.

Why the End-of-Word Flag Is Not Optional

This is the part beginners skip, and it breaks the structure quietly.

After inserting "card", the path c → a → r exists. So does c → a. If you search for "car" by walking the characters and returning "found" when you arrive, you get true — even though "car" was never inserted.

Existing as a path is not the same as being a word

inserted: "card"

search("car")   walk c → a → r   arrived, but is_word = False  →  false ✓
starts_with("car")  same walk, arrival is enough                →  true  ✓

The flag is the only thing distinguishing "a word ends here" from "words pass through here". Both operations walk identically; they differ only in what they check on arrival.

Why Not Just Use a Hash Map?

For exact lookup, a hash map is better — O(1) versus O(length). Use one.

The difference appears with prefixes:

QuestionHash mapTrie
Is "apple" stored?O(1)O(L)
Does anything start with "app"?Scan every keyO(n·L)O(L)
List everything starting with "app"Scan every keyWalk to the node, collect below it
Memory for many shared prefixesFull string eachShared once

The rule

A trie is worth it when you ask about prefixes. Otherwise a hash map wins.

That is why it powers autocomplete, spell-checking, IP routing tables and word-search games — all of which ask "what continues from here?" rather than "is this exact thing present?"

The Two Operations Are the Same Walk

Every trie operation is: start at the root, follow one character at a time.

INSERT                          SEARCH
for each char:                  for each char:
    if no child, create it          if no child → not found
    move down                       move down
mark end-of-word                check the end-of-word flag

Insert creates missing children; search fails on them. Nothing else differs.

Cost

OperationTimeNote
Insert a wordO(L)L = word length
Search a wordO(L)Independent of how many words are stored
Starts-withO(L)The reason the structure exists
SpaceO(total characters)Less with shared prefixes

The time never depends on n, the number of stored words — only on the length of the one you are asking about. A trie holding a million words finds a five-letter word in five steps.

Memory is the real cost

Each node carries a map of children. With a dictionary per node the overhead is significant; a 26-slot array per node is faster but wastes space when most slots are empty.

For a large sparse dictionary a trie can use more memory than storing the strings plainly. The prefix operations are what you are buying it for.

All Problems

ProblemDifficultyPattern
Implement TrieMediumBuilding the structure
Replace WordsMediumShortest-prefix lookup

Suggested order

Implement Trie first — you cannot use one well without having built one. Replace Words then applies it to the job a hash map genuinely cannot do.

On this page