Support word insert, full-word search, and prefix search.
Start with the concrete trace below. It shows the state the algorithm must carry as it runs.
Problem trace
Implement Trie: Each root-to-node path is one shared prefix; terminal state distinguishes a complete word from a mere prefix.
Input and goalSupport word insert, full-word search, and prefix search.
Start with an empty rootThe root has no child before insert("app").
double border complete word
operationinsert("app")existingroot only
Create prefix asetdefault creates the root child keyed by a.
double border complete word
pathroot -a-> a
Create prefix apFrom a, setdefault creates child p for prefix ap.
double border complete word
pathroot -a-> a -p-> ap
Create and mark appCreate the second p child, then store None at app.
double border complete word
pathroot -a-> a -p-> ap -p-> appterminalapp=yes
Reuse app while inserting appleFollow existing a, ap, app; create l->appl then e->apple and mark apple terminal.
double border complete word
operationinsert("apple")createdappl, apple
Reject ap as a full wordsearch("ap") reaches ap but terminal=no, so return false.
double border complete word
querysearch("ap")outcomefalse
Accept ap as a prefixstarts_with("ap") only requires the node to exist, so return true.
double border complete word
querystarts_with("ap")outcometrue
Accept app as a full wordsearch("app") reaches app with terminal=yes.
double border complete word
querysearch("app")resulttrue
Recognize it
Many words share prefixes and queries distinguish prefix existence from complete-word membership.
Keep true
The root-to-node edge labels spell its prefix; terminal is true exactly for inserted complete words.
Reuse it
Store shared prefixes once and attach terminal or payload state to nodes.
Read it this way: The root has no child before insert("app"). Step through the frames to watch the state change. The last frame shows the answer or the stopping condition.
Pattern: Tree of character maps.
Simple idea: Follow one child map per character. Add an end marker after the last
character so a full word can be different from its prefix.
class Trie: def __init__(self) -> None: self.root: dict = {} def insert(self, word: str) -> None: node = self.root for char in word: node = node.setdefault(char, {}) node[None] = True def _walk(self, text: str) -> dict | None: node = self.root for char in text: if char not in node: return None node = node[char] return node def search(self, word: str) -> bool: node = self._walk(word) return node is not None and None in node def starts_with(self, prefix: str) -> bool: return self._walk(prefix) is not None
Cost:O(L) time for each operation and O(totalcharacters) stored space.