PrepStack · Markdown HTML

Trie prefix search

Tree, BST, and trie · HTML

Formal shape

The root is the empty prefix; character-labeled edges make each root-to-node path a prefix. Nodes store a children map and terminal marker/payload. Insert creates missing edges, search also checks terminal, and prefix lookup only requires the path.

Recognition signals

False friends

SignalWhy it is different
One fixed patternA single-pattern method such as KMP uses less memory.
Exact membership onlyA hash set gives expected O(L) with a simpler and often smaller representation; Trie earns its keep through prefixes.
A fixed child array for a huge sparse alphabetAllocating the full alphabet per node wastes space; use a map or compressed trie.

Core invariant

Every Trie node denotes one unique prefix; its children are exactly the next characters occurring after that prefix in inserted words, and terminal is true only at complete word ends.

State, transition, and processing order

ItemDefinition
StateCurrent Trie node, next character position, and each node's children/terminal/optional payload.
TransitionFor character ch, follow children[ch]. Insertion creates a missing edge; lookup fails immediately when the edge is absent.
Frontier / orderA single query follows one prefix path. Combined with grid/backtracking search, a Trie node compresses the remaining candidate words into its subtree.

Python skeleton

class TrieNode:
    def __init__(self):
        self.children = {}
        self.terminal = False

class Trie:
    def __init__(self):
        self.root = TrieNode()
    def insert(self, word):
        node = self.root
        for ch in word:
            node = node.children.setdefault(ch, TrieNode())
        node.terminal = True
    def _walk(self, text):
        node = self.root
        for ch in text:
            if ch not in node.children: return None
            node = node.children[ch]
        return node
    def search(self, word):
        node = self._walk(word)
        return bool(node and node.terminal)
    def starts_with(self, prefix):
        return self._walk(prefix) is not None

Correctness sketch

  1. Insertion creates or reuses one edge per character; induction makes the terminal path spell exactly the inserted word.
  2. walk follows only an edge matching the next character; a missing edge proves no inserted word has that prefix.
  3. After a full path, terminal distinguishes a complete inserted word from a path that only prefixes longer words, making both query forms correct.

Complexity

TimeSpaceParameters
Expected O(L) per insert/search/prefix with hash-mapped childrenO(T), where T is the number of distinct prefix-character nodes, at most total inserted charactersL is operation string length and T deduplicated prefix nodes.

Edge cases

Error patterns

PatternWhy it fails / fix
Checking only path existence in searchThat incorrectly accepts strings that are merely prefixes; full-word search must check terminal.
Requiring terminal for starts_withA valid prefix need not itself be an inserted word.
Hard-coding 26 children for every alphabetLarge or noncontiguous character domains waste memory or produce invalid indexing.
Restarting at root during every DFS stepCarry the current Trie node so extending a path costs one edge, not a repeated prefix walk.

Selection and exclusion rules

RelationTemplateBoundary

Original micro-example

PartDetail
Resultsearch('tea') and starts_with('te') are true, while search('te') is false.
SetupInsert 'tea' and 'team'.
TraceBoth words share t-e-a; the a-node is terminal and still has child m.

Recall prompts

My notes