{
  "id": "trees/trie",
  "version": 1,
  "deterministic": true,
  "url": "/dsa/trees/trie",
  "topic": {
    "slug": "trees",
    "title": "Trees"
  },
  "title": "Trie (Prefix Tree)",
  "tagline": "Words that start the same share the same path — so autocomplete is free.",
  "vizKind": "trie",
  "complexity": {
    "time": {
      "best": "O(L)",
      "average": "O(L)",
      "worst": "O(L)"
    },
    "space": "O(total characters)",
    "growth": "constant",
    "note": "Insert and search cost O(L), the length of the *word* — completely independent of how many words the trie holds. A million words or ten, looking up 'card' takes four steps. The price is memory: a node per character, though shared prefixes claw a lot of it back."
  },
  "code": {
    "javascript": "class Node {\n  constructor(char) {\n    this.char = char;\n    this.children = {};   // one child per next letter\n    this.isWord = false;\n  }\n}\n\nfunction insert(root, word) {\n  let cur = root;\n  for (const ch of word) {\n    // Reuse the path if it already exists — that's the whole point.\n    if (!cur.children[ch]) cur.children[ch] = new Node(ch);\n    cur = cur.children[ch];\n  }\n  cur.isWord = true;      // a word ends here\n}\n\nfunction startsWith(root, prefix) {\n  let cur = root;\n  for (const ch of prefix) {\n    if (!cur.children[ch]) return false;   // no such path\n    cur = cur.children[ch];\n  }\n  return true;            // every word below this node has the prefix\n}",
    "python": "class Node:\n    def __init__(self, char):\n        self.char = char\n        self.children = {}    # one child per next letter\n        self.is_word = False\n\n\n\ndef insert(root, word):\n    cur = root\n    for ch in word:\n        # Reuse the path if it already exists — that's the whole point.\n        if ch not in cur.children: cur.children[ch] = Node(ch)\n        cur = cur.children[ch]\n\n    cur.is_word = True        # a word ends here\n\n\ndef starts_with(root, prefix):\n    cur = root\n    for ch in prefix:\n        if ch not in cur.children: return False   # no such path\n        cur = cur.children[ch]\n\n    return True               # every word below has the prefix\n",
    "java": "class Node {\n  char ch;\n  Map<Character, Node> children = new HashMap<>();\n  boolean isWord = false;\n  Node(char ch) { this.ch = ch; }\n}\n\n\nvoid insert(Node root, String word) {\n  Node cur = root;\n  for (char ch : word.toCharArray()) {\n    // Reuse the path if it already exists — that's the whole point.\n    cur.children.putIfAbsent(ch, new Node(ch));\n    cur = cur.children.get(ch);\n  }\n  cur.isWord = true;      // a word ends here\n}\n\nboolean startsWith(Node root, String prefix) {\n  Node cur = root;\n  for (char ch : prefix.toCharArray()) {\n    if (!cur.children.containsKey(ch)) return false;  // no such path\n    cur = cur.children.get(ch);\n  }\n  return true;            // every word below has the prefix\n}",
    "cpp": "struct Node {\n  char ch;\n  map<char, Node*> children;   // one child per next letter\n  bool isWord = false;\n  Node(char c) : ch(c) {}\n};\n\n\nvoid insert(Node* root, string word) {\n  Node* cur = root;\n  for (char ch : word) {\n    // Reuse the path if it already exists — that's the whole point.\n    if (!cur->children.count(ch)) cur->children[ch] = new Node(ch);\n    cur = cur->children[ch];\n  }\n  cur->isWord = true;     // a word ends here\n}\n\nbool startsWith(Node* root, string prefix) {\n  Node* cur = root;\n  for (char ch : prefix) {\n    if (!cur->children.count(ch)) return false;   // no such path\n    cur = cur->children[ch];\n  }\n  return true;            // every word below has the prefix\n}"
  },
  "defaultInput": [
    0
  ],
  "defaultTarget": null,
  "inputHint": "Pick a word set: 1 = car/card/cat/dog, 2 = to/tea/ted/ten/in/inn, 3 = go/gone/good/god.",
  "pitfalls": [
    {
      "wrong": "Forgetting the 'is a word ends here' flag.",
      "right": "Without it you can't tell 'car' (a real word) from the 'car' inside 'card' (just a prefix). The path existing doesn't mean the word exists."
    },
    {
      "wrong": "Storing the whole word at each node.",
      "right": "That throws away the entire benefit. The word IS the path — that's what makes prefixes shared and memory manageable."
    },
    {
      "wrong": "Using a fixed 26-slot array per node without thinking.",
      "right": "Fast, but 26 pointers per node adds up brutally on a sparse trie. A hash map per node uses far less memory when most letters are unused."
    },
    {
      "wrong": "Reaching for a trie when a hash set would do.",
      "right": "A hash set does exact lookup in O(1) with far less memory. Only use a trie when you need *prefixes* — autocomplete, wildcards, longest-common-prefix."
    }
  ],
  "quiz": [
    {
      "q": "Where is the word actually stored in a trie?",
      "options": [
        "In the leaf node",
        "Nowhere — the word is the path of letters from the root to the node",
        "In the root",
        "In a separate array"
      ],
      "answer": 1,
      "why": "Each edge is a letter, and the journey from the root spells the word. That's why the node needs a flag just to say a word ends there — the node itself doesn't contain it."
    },
    {
      "q": "How long does it take to find every word starting with 'ca'?",
      "options": [
        "O(n), where n is the number of words",
        "You walk 2 letters, and everything below that node is an answer",
        "O(n log n)",
        "You must check each word's prefix"
      ],
      "answer": 1,
      "why": "Walk one node per letter of the prefix, then stop. Everything in the subtree beneath you has that prefix, by construction — no searching and no comparing, however many millions of words are stored."
    },
    {
      "q": "When should you NOT use a trie?",
      "options": [
        "For autocomplete",
        "When you only need exact lookups — a hash set is O(1) and uses far less memory",
        "For prefix matching",
        "For a spell checker"
      ],
      "answer": 1,
      "why": "A trie's advantage is entirely about prefixes. If you only ever ask 'is this exact word present?', a hash set answers in O(1) with a fraction of the memory."
    }
  ],
  "problems": [
    {
      "name": "Implement Trie (Prefix Tree)",
      "difficulty": "Medium",
      "url": "https://leetcode.com/problems/implement-trie-prefix-tree/"
    },
    {
      "name": "Design Add and Search Words Data Structure",
      "difficulty": "Medium",
      "url": "https://leetcode.com/problems/design-add-and-search-words-data-structure/"
    },
    {
      "name": "Word Search II",
      "difficulty": "Hard",
      "url": "https://leetcode.com/problems/word-search-ii/"
    },
    {
      "name": "Longest Common Prefix",
      "difficulty": "Easy",
      "url": "https://leetcode.com/problems/longest-common-prefix/"
    }
  ],
  "trace": {
    "note": "Each frame is one immutable step: data snapshot, pointers, per-index roles, executing code line, and a one-sentence explanation.",
    "length": 22,
    "frames": [
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [],
              "isWord": false
            }
          ],
          "rootId": "root"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 1,
        "variables": {
          "words": "car card cat dog"
        },
        "explanation": "Store these words: car, card, cat, dog. A trie doesn't store them as separate strings — it stores them as *paths*, and words that start the same way share the same path.",
        "stats": {
          "comparisons": 0,
          "swaps": 0
        },
        "accent": "active"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [],
              "isWord": false,
              "role": "swap"
            }
          ],
          "rootId": "root",
          "probe": "car"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 14,
        "variables": {
          "word": "car",
          "letter": "c",
          "reused": false
        },
        "explanation": "No 'c' from here yet, so branch off with a new node.",
        "stats": {
          "comparisons": 1,
          "swaps": 0
        },
        "accent": "swap"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [],
              "isWord": false,
              "role": "swap"
            }
          ],
          "rootId": "root",
          "probe": "car"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 14,
        "variables": {
          "word": "car",
          "letter": "a",
          "reused": false
        },
        "explanation": "No 'a' from here yet, so branch off with a new node.",
        "stats": {
          "comparisons": 2,
          "swaps": 0
        },
        "accent": "swap"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [],
              "isWord": false,
              "role": "swap"
            }
          ],
          "rootId": "root",
          "probe": "car"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 14,
        "variables": {
          "word": "car",
          "letter": "r",
          "reused": false
        },
        "explanation": "No 'r' from here yet, so branch off with a new node.",
        "stats": {
          "comparisons": 3,
          "swaps": 0
        },
        "accent": "swap"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c"
              ],
              "isWord": false
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r"
              ],
              "isWord": false
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [],
              "isWord": true,
              "role": "found"
            }
          ],
          "rootId": "root",
          "probe": "car"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 17,
        "variables": {
          "stored": "car",
          "sharedNodes": 0
        },
        "explanation": "Mark this node as the end of a word (the double ring). Note the node itself doesn't hold \"car\" — the *path from the root* spells it.",
        "stats": {
          "comparisons": 3,
          "swaps": 0
        },
        "accent": "found"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c"
              ],
              "isWord": false,
              "role": "pivot"
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false,
              "role": "pivot"
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r"
              ],
              "isWord": false
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [],
              "isWord": true
            }
          ],
          "rootId": "root",
          "probe": "card"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 13,
        "variables": {
          "word": "card",
          "letter": "c",
          "reused": true
        },
        "explanation": "'c' already has a path from here — so we walk down the one that exists rather than making a new node. This is the sharing: \"card\" is reusing a prefix another word already built.",
        "stats": {
          "comparisons": 4,
          "swaps": 1
        },
        "accent": "pivot"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c"
              ],
              "isWord": false,
              "role": "pivot"
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false,
              "role": "pivot"
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r"
              ],
              "isWord": false,
              "role": "pivot"
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [],
              "isWord": true
            }
          ],
          "rootId": "root",
          "probe": "card"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 13,
        "variables": {
          "word": "card",
          "letter": "a",
          "reused": true
        },
        "explanation": "'a' already has a path from here — so we walk down the one that exists rather than making a new node. This is the sharing: \"card\" is reusing a prefix another word already built.",
        "stats": {
          "comparisons": 5,
          "swaps": 2
        },
        "accent": "pivot"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c"
              ],
              "isWord": false,
              "role": "pivot"
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false,
              "role": "pivot"
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r"
              ],
              "isWord": false,
              "role": "pivot"
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [],
              "isWord": true,
              "role": "pivot"
            }
          ],
          "rootId": "root",
          "probe": "card"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 13,
        "variables": {
          "word": "card",
          "letter": "r",
          "reused": true
        },
        "explanation": "'r' already has a path from here — so we walk down the one that exists rather than making a new node. This is the sharing: \"card\" is reusing a prefix another word already built.",
        "stats": {
          "comparisons": 6,
          "swaps": 3
        },
        "accent": "pivot"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [
                "t3-d"
              ],
              "isWord": true,
              "role": "active"
            },
            {
              "id": "t3-d",
              "char": "d",
              "children": [],
              "isWord": false,
              "role": "swap"
            }
          ],
          "rootId": "root",
          "probe": "card"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 14,
        "variables": {
          "word": "card",
          "letter": "d",
          "reused": false
        },
        "explanation": "No 'd' from here yet, so branch off with a new node.",
        "stats": {
          "comparisons": 7,
          "swaps": 3
        },
        "accent": "swap"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c"
              ],
              "isWord": false
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r"
              ],
              "isWord": false
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [
                "t3-d"
              ],
              "isWord": true
            },
            {
              "id": "t3-d",
              "char": "d",
              "children": [],
              "isWord": true,
              "role": "found"
            }
          ],
          "rootId": "root",
          "probe": "card"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 17,
        "variables": {
          "stored": "card",
          "sharedNodes": 3
        },
        "explanation": "Mark this node as the end of a word (the double ring). Note the node itself doesn't hold \"card\" — the *path from the root* spells it.",
        "stats": {
          "comparisons": 7,
          "swaps": 3
        },
        "accent": "found"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c"
              ],
              "isWord": false,
              "role": "pivot"
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false,
              "role": "pivot"
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r"
              ],
              "isWord": false
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [
                "t3-d"
              ],
              "isWord": true
            },
            {
              "id": "t3-d",
              "char": "d",
              "children": [],
              "isWord": true
            }
          ],
          "rootId": "root",
          "probe": "cat"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 13,
        "variables": {
          "word": "cat",
          "letter": "c",
          "reused": true
        },
        "explanation": "'c' already has a path from here — so we walk down the one that exists rather than making a new node. This is the sharing: \"cat\" is reusing a prefix another word already built.",
        "stats": {
          "comparisons": 8,
          "swaps": 4
        },
        "accent": "pivot"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c"
              ],
              "isWord": false,
              "role": "pivot"
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false,
              "role": "pivot"
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r"
              ],
              "isWord": false,
              "role": "pivot"
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [
                "t3-d"
              ],
              "isWord": true
            },
            {
              "id": "t3-d",
              "char": "d",
              "children": [],
              "isWord": true
            }
          ],
          "rootId": "root",
          "probe": "cat"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 13,
        "variables": {
          "word": "cat",
          "letter": "a",
          "reused": true
        },
        "explanation": "'a' already has a path from here — so we walk down the one that exists rather than making a new node. This is the sharing: \"cat\" is reusing a prefix another word already built.",
        "stats": {
          "comparisons": 9,
          "swaps": 5
        },
        "accent": "pivot"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r",
                "t4-t"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [
                "t3-d"
              ],
              "isWord": true
            },
            {
              "id": "t3-d",
              "char": "d",
              "children": [],
              "isWord": true
            },
            {
              "id": "t4-t",
              "char": "t",
              "children": [],
              "isWord": false,
              "role": "swap"
            }
          ],
          "rootId": "root",
          "probe": "cat"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 14,
        "variables": {
          "word": "cat",
          "letter": "t",
          "reused": false
        },
        "explanation": "No 't' from here yet, so branch off with a new node.",
        "stats": {
          "comparisons": 10,
          "swaps": 5
        },
        "accent": "swap"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c"
              ],
              "isWord": false
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r",
                "t4-t"
              ],
              "isWord": false
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [
                "t3-d"
              ],
              "isWord": true
            },
            {
              "id": "t3-d",
              "char": "d",
              "children": [],
              "isWord": true
            },
            {
              "id": "t4-t",
              "char": "t",
              "children": [],
              "isWord": true,
              "role": "found"
            }
          ],
          "rootId": "root",
          "probe": "cat"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 17,
        "variables": {
          "stored": "cat",
          "sharedNodes": 5
        },
        "explanation": "Mark this node as the end of a word (the double ring). Note the node itself doesn't hold \"cat\" — the *path from the root* spells it.",
        "stats": {
          "comparisons": 10,
          "swaps": 5
        },
        "accent": "found"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c",
                "t5-d"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r",
                "t4-t"
              ],
              "isWord": false
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [
                "t3-d"
              ],
              "isWord": true
            },
            {
              "id": "t3-d",
              "char": "d",
              "children": [],
              "isWord": true
            },
            {
              "id": "t4-t",
              "char": "t",
              "children": [],
              "isWord": true
            },
            {
              "id": "t5-d",
              "char": "d",
              "children": [],
              "isWord": false,
              "role": "swap"
            }
          ],
          "rootId": "root",
          "probe": "dog"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 14,
        "variables": {
          "word": "dog",
          "letter": "d",
          "reused": false
        },
        "explanation": "No 'd' from here yet, so branch off with a new node.",
        "stats": {
          "comparisons": 11,
          "swaps": 5
        },
        "accent": "swap"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c",
                "t5-d"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r",
                "t4-t"
              ],
              "isWord": false
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [
                "t3-d"
              ],
              "isWord": true
            },
            {
              "id": "t3-d",
              "char": "d",
              "children": [],
              "isWord": true
            },
            {
              "id": "t4-t",
              "char": "t",
              "children": [],
              "isWord": true
            },
            {
              "id": "t5-d",
              "char": "d",
              "children": [
                "t6-o"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t6-o",
              "char": "o",
              "children": [],
              "isWord": false,
              "role": "swap"
            }
          ],
          "rootId": "root",
          "probe": "dog"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 14,
        "variables": {
          "word": "dog",
          "letter": "o",
          "reused": false
        },
        "explanation": "No 'o' from here yet, so branch off with a new node.",
        "stats": {
          "comparisons": 12,
          "swaps": 5
        },
        "accent": "swap"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c",
                "t5-d"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r",
                "t4-t"
              ],
              "isWord": false
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [
                "t3-d"
              ],
              "isWord": true
            },
            {
              "id": "t3-d",
              "char": "d",
              "children": [],
              "isWord": true
            },
            {
              "id": "t4-t",
              "char": "t",
              "children": [],
              "isWord": true
            },
            {
              "id": "t5-d",
              "char": "d",
              "children": [
                "t6-o"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t6-o",
              "char": "o",
              "children": [
                "t7-g"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t7-g",
              "char": "g",
              "children": [],
              "isWord": false,
              "role": "swap"
            }
          ],
          "rootId": "root",
          "probe": "dog"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 14,
        "variables": {
          "word": "dog",
          "letter": "g",
          "reused": false
        },
        "explanation": "No 'g' from here yet, so branch off with a new node.",
        "stats": {
          "comparisons": 13,
          "swaps": 5
        },
        "accent": "swap"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c",
                "t5-d"
              ],
              "isWord": false
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r",
                "t4-t"
              ],
              "isWord": false
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [
                "t3-d"
              ],
              "isWord": true
            },
            {
              "id": "t3-d",
              "char": "d",
              "children": [],
              "isWord": true
            },
            {
              "id": "t4-t",
              "char": "t",
              "children": [],
              "isWord": true
            },
            {
              "id": "t5-d",
              "char": "d",
              "children": [
                "t6-o"
              ],
              "isWord": false
            },
            {
              "id": "t6-o",
              "char": "o",
              "children": [
                "t7-g"
              ],
              "isWord": false
            },
            {
              "id": "t7-g",
              "char": "g",
              "children": [],
              "isWord": true,
              "role": "found"
            }
          ],
          "rootId": "root",
          "probe": "dog"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 17,
        "variables": {
          "stored": "dog",
          "sharedNodes": 5
        },
        "explanation": "Mark this node as the end of a word (the double ring). Note the node itself doesn't hold \"dog\" — the *path from the root* spells it.",
        "stats": {
          "comparisons": 13,
          "swaps": 5
        },
        "accent": "found"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c",
                "t5-d"
              ],
              "isWord": false
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r",
                "t4-t"
              ],
              "isWord": false
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [
                "t3-d"
              ],
              "isWord": true
            },
            {
              "id": "t3-d",
              "char": "d",
              "children": [],
              "isWord": true
            },
            {
              "id": "t4-t",
              "char": "t",
              "children": [],
              "isWord": true
            },
            {
              "id": "t5-d",
              "char": "d",
              "children": [
                "t6-o"
              ],
              "isWord": false
            },
            {
              "id": "t6-o",
              "char": "o",
              "children": [
                "t7-g"
              ],
              "isWord": false
            },
            {
              "id": "t7-g",
              "char": "g",
              "children": [],
              "isWord": true
            }
          ],
          "rootId": "root",
          "probe": "ca"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 20,
        "variables": {
          "prefix": "ca"
        },
        "explanation": "Now the payoff. Find every word starting with \"ca\". A list of strings would have to check every single word. Watch what a trie does instead.",
        "stats": {
          "comparisons": 13,
          "swaps": 5
        },
        "accent": "active"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c",
                "t5-d"
              ],
              "isWord": false,
              "role": "compare"
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false,
              "role": "compare"
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r",
                "t4-t"
              ],
              "isWord": false
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [
                "t3-d"
              ],
              "isWord": true
            },
            {
              "id": "t3-d",
              "char": "d",
              "children": [],
              "isWord": true
            },
            {
              "id": "t4-t",
              "char": "t",
              "children": [],
              "isWord": true
            },
            {
              "id": "t5-d",
              "char": "d",
              "children": [
                "t6-o"
              ],
              "isWord": false
            },
            {
              "id": "t6-o",
              "char": "o",
              "children": [
                "t7-g"
              ],
              "isWord": false
            },
            {
              "id": "t7-g",
              "char": "g",
              "children": [],
              "isWord": true
            }
          ],
          "rootId": "root",
          "probe": "ca"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 23,
        "variables": {
          "prefix": "ca",
          "at": "c",
          "steps": 1
        },
        "explanation": "Follow 'c'. We've walked 1 letter — one step per letter of the prefix, and nothing else.",
        "stats": {
          "comparisons": 14,
          "swaps": 5
        },
        "accent": "compare"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c",
                "t5-d"
              ],
              "isWord": false,
              "role": "compare"
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false,
              "role": "compare"
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r",
                "t4-t"
              ],
              "isWord": false,
              "role": "compare"
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [
                "t3-d"
              ],
              "isWord": true
            },
            {
              "id": "t3-d",
              "char": "d",
              "children": [],
              "isWord": true
            },
            {
              "id": "t4-t",
              "char": "t",
              "children": [],
              "isWord": true
            },
            {
              "id": "t5-d",
              "char": "d",
              "children": [
                "t6-o"
              ],
              "isWord": false
            },
            {
              "id": "t6-o",
              "char": "o",
              "children": [
                "t7-g"
              ],
              "isWord": false
            },
            {
              "id": "t7-g",
              "char": "g",
              "children": [],
              "isWord": true
            }
          ],
          "rootId": "root",
          "probe": "ca"
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 23,
        "variables": {
          "prefix": "ca",
          "at": "a",
          "steps": 2
        },
        "explanation": "Follow 'a'. We've walked 2 letters — one step per letter of the prefix, and nothing else.",
        "stats": {
          "comparisons": 15,
          "swaps": 5
        },
        "accent": "compare"
      },
      {
        "data": {
          "nodes": [
            {
              "id": "root",
              "char": "",
              "children": [
                "t0-c",
                "t5-d"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t0-c",
              "char": "c",
              "children": [
                "t1-a"
              ],
              "isWord": false,
              "role": "active"
            },
            {
              "id": "t1-a",
              "char": "a",
              "children": [
                "t2-r",
                "t4-t"
              ],
              "isWord": false,
              "role": "found"
            },
            {
              "id": "t2-r",
              "char": "r",
              "children": [
                "t3-d"
              ],
              "isWord": true,
              "role": "found"
            },
            {
              "id": "t3-d",
              "char": "d",
              "children": [],
              "isWord": true,
              "role": "found"
            },
            {
              "id": "t4-t",
              "char": "t",
              "children": [],
              "isWord": true,
              "role": "found"
            },
            {
              "id": "t5-d",
              "char": "d",
              "children": [
                "t6-o"
              ],
              "isWord": false
            },
            {
              "id": "t6-o",
              "char": "o",
              "children": [
                "t7-g"
              ],
              "isWord": false
            },
            {
              "id": "t7-g",
              "char": "g",
              "children": [],
              "isWord": true
            }
          ],
          "rootId": "root",
          "probe": "ca",
          "found": [
            "car",
            "card",
            "cat"
          ]
        },
        "pointers": [],
        "highlights": [],
        "codeLine": 25,
        "variables": {
          "prefix": "ca",
          "matches": "car card cat",
          "lettersWalked": 2
        },
        "explanation": "Done — and here's the magic. We walked 2 letters, and now *everything below this node* is an answer: car, card, cat. We didn't search for them. We didn't compare them. They were simply there, sitting under the path. That is why autocomplete is instant even over millions of words.",
        "stats": {
          "comparisons": 15,
          "swaps": 5
        },
        "accent": "found"
      }
    ]
  }
}