Skip to content
AI360Xpert
Beta
Difficulty: MediumTries

Implement Trie (Prefix Tree)

Problem in Plain English

Implement a prefix tree that inserts lowercase words, reports whether a full word was inserted, and reports whether any inserted word starts with a given prefix. Each operation should cost time proportional to the word length, not the number of stored words.

Problem Statement

A trie, pronounced try and also called a prefix tree, is a tree data structure that stores strings so that words sharing a prefix share nodes on one path.

Implement the Trie class with void insert(word), which stores word; boolean search(word), which returns true only if word was inserted as a complete word; and boolean startsWith(prefix), which returns true if any inserted word begins with prefix.

Constraints

  • Word and prefix lengths satisfy 1≤m≤20001 \leq m \leq 2000.
  • word and prefix consist only of lowercase English letters.
  • There are at most 3×1043 \times 10^4 total insert, search and prefix queries.

Examples

Example 1

Input
["Trie","insert","search","search","startsWith","insert","search"] [[],["apple"],["apple"],["app"],["app"],["app"],["app"]]
Output
[null,null,true,false,true,null,true]

After inserting apple, app is only a prefix until it is inserted itself, at which point searching for app returns true.

Example 2

Input
["Trie","search","startsWith","insert","insert","search","search"] [[],["a"],["a"],["a"],["a"],["a"],["aa"]]
Output
[null,false,false,null,null,true,false]

Both queries on an empty structure fail. Duplicate insertion of a is harmless; a exists exactly once as a word, while the longer aa still has no path.

Example 3

Input
["Trie","insert","insert","search","startsWith","search","startsWith"] [[],["app"],["apple"],["app"],["appl"],["appl"],["apricot"]]
Output
[null,null,null,true,true,false,false]

Inserting apple reuses the app path without clearing its word-end flag. appl is a prefix only; apricot fails at the missing r branch even though ap is shared.

Intuition

A path spells a prefix, while a separate word-end flag says whether that prefix was inserted as a whole word. After inserting apple, the path for app exists but its last node is not terminal. Inserting app only marks that existing node; it must leave the longer apple path intact. A set can model the same semantics, but must scan stored words to answer prefix queries.

Approaches

Hash Set Scan

Solution Details

Reveal Hash Set Scan: intuition, complexity, and code

Hints

Hint 1
Picture each word as a path from the root, with one node per letter and shared prefixes sharing nodes.
Hint 2
A boolean on each node records whether some inserted word ends there, which is what separates search from startsWith.
Hint 3
Both lookups walk the same path letter by letter; only the final check on the flag differs.

Edge Cases

  • A word that is a prefix of another word, such as app inside apple, which needs the flag to tell them apart.
  • A query longer than any inserted word that still follows a live prefix for a while.
  • Inserting the same word twice, which should simply set the flag again without duplicating nodes.
  • Queries on an empty structure are false because inputs are nonempty; a 2000-character word is handled iteratively, without recursion.
  • Separate Trie instances must own separate roots or sets, so inserting into one does not affect another.

Common Mistakes and Interview Tips

  • Forgetting to set the word-end flag on insert, so every search returns false.
  • Returning true from search whenever the path exists, without verifying the word-end flag.
  • Creating a fresh chain for a word that shares a prefix instead of reusing the existing nodes.
  • Calling hash-set insertion constant time without accounting for hashing a previously unseen string.
  • Putting root or children in shared static/class state, which leaks stored words between instances.

Key Takeaway

When many strings share prefixes, store one node per character and answer word and prefix queries with a single walk whose cost depends only on the query length.