Tries · Trie Fundamentals

Trie Prefix Matching

Marking every complete word in a trie, then walking a candidate word's own path checking that EVERY node along that path (not just the final one) is itself marked as a complete word - the candidate only qualifies if every one of its prefixes was independently inserted as a full word too.

  • 4 min read
  • 7 practice questions
  • 2 graded problems
On this page
  1. Description
  2. The approach
  3. A second flavor: stop at the first end mark
  4. Where you'll see it
  5. Which tool for which job?
  6. Common mistakes
  7. Check yourself
  8. Key takeaways
  9. Quick revise
  10. Practice

Description

Some questions care about every prefix of a word, not just the word: "the longest word that can be built one letter at a time from other words in the list", or "replace each word in a sentence with the shortest dictionary root it starts with". A trie holds all the prefixes on one path, so each question becomes a single walk.

This skill covers three versions of that walk: requiring an end mark on every node, stopping at the first end mark, and keeping the last one. It also covers the tie-break and "no answer" rules that make the results well defined.

We'll go from simple to more technical:

  1. The pattern: the longest word whose every prefix is also a word.
  2. A second flavor: Replace Words, stopping at the first end mark.
  3. Where prefix walks show up (stemming, URL routing, IP longest-prefix match).
  4. What breaks it: checking only the full word, shortest versus longest, ties, no answer.

The approach

Java

boolean allPrefixesAreWords(String word) {
    TrieNode node = root;
    for (char c : word.toCharArray()) {
        node = node.next[c - 'a'];
        if (node == null || !node.isEnd) return false;   // this prefix isn't itself a stored word
    }
    return true;
}

String longestWordWithAllPrefixes(String[] words) {
    for (String w : words) insert(w);
    String best = "";
    for (String w : words) {
        if (allPrefixesAreWords(w) && (w.length() > best.length()
                || (w.length() == best.length() && w.compareTo(best) < 0))) {
            best = w;                                    // longer, or same length and smaller
        }
    }
    return best;
}

Python

def all_prefixes_are_words(word: str) -> bool:
    node = root
    for c in word:
        node = node.next.get(c)
        if node is None or not node.is_end:
            return False                                 # this prefix isn't itself a stored word
    return True


def longest_word_with_all_prefixes(words: list[str]) -> str:
    for w in words:
        insert(w)
    best = ""
    for w in words:
        if all_prefixes_are_words(w) and (len(w) > len(best) or (len(w) == len(best) and w < best)):
            best = w                                     # longer, or same length and smaller
    return best

"bread" qualifies only if "b", "br", "bre", "brea" and "bread" are all in the list - every node on its path must carry an end mark, not just the last. A plain search(w) checks only the last one. The tie-break (lexicographically smallest among equally long words) makes the answer unique, and "" is the answer when no word qualifies, for instance when there are no one-letter words.

A second flavor: stop at the first end mark

Replace each word by the shortest root that is a prefix of it ("cattle" with root "cat" becomes "cat"):

Java

String shortestRoot(String word) {
    TrieNode node = root;
    for (int i = 0; i < word.length(); i++) {
        node = node.next[word.charAt(i) - 'a'];
        if (node == null) return word;                 // no root is a prefix
        if (node.isEnd) return word.substring(0, i + 1);   // the first end mark is the shortest root
    }
    return word;
}

Python

def shortest_root(word: str) -> str:
    node = root
    for i, c in enumerate(word):
        node = node.next.get(c)
        if node is None:
            return word                                  # no root is a prefix
        if node.is_end:
            return word[:i + 1]                          # the first end mark is the shortest root
    return word

Walking down the word's own path meets the roots in order of length, so the first end mark is the shortest. Continuing to the last end mark returns the longest root instead ("cat" and "catt" for "cattle" would give "catt").

Where you'll see it

Stemming and lemmatization shorten words to dictionary roots; URL routers match the most (or least) specific registered path prefix; IP forwarding picks the longest matching network prefix - the same walk, keeping the last end mark seen. Checking that every intermediate step is itself valid (every prefix a word) is how incremental builds validate each step of a chain.

Which tool for which job?

You needUse
Every prefix of a word is itself a wordone walk, every node end-marked
The longest such worda DFS over end-marked children only
The shortest dictionary root of a wordstop at the first end mark
The most specific matching rule (routes, IPs)keep the last end mark seen
Every pattern occurring anywhere in a textAho-Corasick

Common mistakes

MistakeWhat happensDo this instead
Checking only the full word"bread" passes without "brea"every node on the path needs its end mark
Keeping the last end mark for the shortest root"cattle" becomes "catt"stop at the first end mark
No tie-breakequally long answers come out in input orderlongest, then lexicographically smallest
No "no answer" casea word with no root is droppedreturn the word itself (or "")
A set of prefix stringsO(L^2) characters built per wordwalk the trie once

Check yourself

Try to answer before opening each one - recalling beats re-reading.

1. Why isn't search(word) enough for "every prefix is also a word"?

Show answer

search only checks the end mark at the last node. "bread" can be in the list while "brea" isn't; every node on the path must be marked.

2. How does a single walk find the shortest root of a word?

Show answer

Walking the word's path meets roots in increasing length, so the first node with an end mark is the shortest root. Stop there.

3. What does the longest-word question return when no word qualifies?

Show answer

An empty string - for example when the list has no one-letter words, since every qualifying word must start with one.

Key takeaways

  • A word's prefixes all lie on its path; one walk checks them.
  • "Every prefix is a word": every node on the path needs an end mark.
  • Shortest root: stop at the first end mark; longest: keep the last.
  • Make tie-breaks and "no answer" explicit.

Quick revise

The whole skill on one page, for the night before an interview.

This page puts the lesson and the deep dive together. Skim it before practice or an interview, and go back to the full lesson for anything you don't recognize.

Pick the tool

You needUse
All prefixes are wordswalk, every node marked
Longest such wordDFS over marked children
Shortest rootfirst end mark
Most specific matchlast end mark
Patterns anywhere in textAho-Corasick

Snippets worth knowing by heart

Java

for (int i = 0; i < word.length(); i++) {
    node = node.next[word.charAt(i) - 'a'];
    if (node == null) return word;
    if (node.isEnd) return word.substring(0, i + 1);    // first end mark = shortest root
}
return word;

Python

def dfs(node, acc):                       # longest word whose prefixes are all words
    global best
    if len(acc) > len(best):
        best = acc
    for c in sorted(node.next):           # a to z: ties go to the smaller word
        if node.next[c].is_end:
            dfs(node.next[c], acc + c)

The traps

  • Only the full word checked: "bread" passes without "brea" in the dictionary. Require the end mark at every node.
  • First versus last end mark: keeping the last one gives the longest root, not the shortest. Stop at the first.
  • Ties: equally long answers come out in input order. Break ties lexicographically.
  • No answer: a word with no root is dropped. Return the word itself, or "".

Staff-level points, one line each

  • a, aa, ... up to 2,000: a set builds 1,335,334,000 prefix characters, the trie walks 2,001,000.
  • A DFS over end-marked children matched scanning every word on 300 lists.
  • Routers keep the last route seen; a binary trie matched brute force on 5,000 lookups.
  • Shortest roots: "the cat was rat by the bat"; longest: "the catt was rat by the bat".
  • Aho-Corasick found she, he and hers in "ushers" in one pass.

Say it in an interview

  • "All of a word's prefixes are on its path, so one walk checks them."
  • "For the shortest root I stop at the first end mark."
  • "Longest-prefix match keeps the last match, like an IP router."
  • "For patterns anywhere in the text, I'd add failure links: Aho-Corasick."

Practice

This skill comes with 7 multiple-choice questions that tell you which misconception a wrong answer reveals and 2 graded problems. Your answers are graded and your mastery is tracked, so you'll know when the skill holds up. Running code and saving progress need a free account.

Practice Trie Prefix Matching free

Longest Word with All Prefixes

MediumProCoding problemJava · Python

Given an array of distinct lowercase words, find the longest word such that every one of its prefixes is also present in the array as a complete word. If several words tie for longest, return the lexicographically smallest.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Replace Words

MediumProCoding problemJava · Python

You have a list of word roots and a sentence. Replace each word of the sentence that begins with a root by that root; if several roots fit, use the shortest. Words that begin with no root stay as they are. Return the sentence with words separated by single spaces.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Practice Trie Prefix Matching free

No card needed. Lessons, practice questions and easy problems are free forever.

Free plan, no card · 7-day Pro trial · Cancel anytime