State Space Exploration Superset Professional Playbook
Overview and Reading Path
Use this guide when a problem can be solved by recursive calls, graph/grid movement, choices, memoization, BFS, tree traversal, string positions, or range splitting, and you need to decide what the call really means.
Read in this order:
- Learn the superset family map.
- Learn the five universal questions.
- Learn the state-versus-unit vocabulary bridge.
- Learn the forward-work versus upward-work distinction.
- Translate the problem with the unified workflow.
- Pick the execution family.
- Use the merged translation table for pattern recognition.
- Study the canonical examples.
- Study the dry runs.
- Use the decision rules, failure modes, performance notes, and cheat sheets.
This guide intentionally repeats the same questions from several angles. That is useful because most mistakes come from choosing the engine too early.
Do not start with:
This is recursion.
This is DP.
This is graph.
This is string.
Start with:
What does one call/state/unit know?
What can it legally do next?
What must it return?
Core Vocabulary
| Term | Meaning |
|---|---|
| State | The minimum facts needed to continue correctly |
| Unit | A range, subtree, token interval, or segment owned by one recombine call |
| Choice | A legal action available from a state |
| Split | A divide/recombine choice that creates child units |
| Transition | The move from one state to another |
| Base case | The smallest unit or terminal state solved directly |
| Stop condition | A rule that records, rejects, returns, or finishes |
| Path | The concrete construction built by backtracking |
| Tracker | Fast legality memory such as used values, occupied columns, or visited cells |
| Memo key | The state fields that determine a repeated future answer |
| Frontier | The queue/layer of states currently ready to process |
| Summary | The compact answer returned by a child call |
| Cross work | Work needed between child units, such as cross inversions or crossing subarray |
| Recombine | Building a parent answer from child summaries |
| String state | Index, pair, path, center, interval, trie node, automaton node, or window |
Beginner Mental Model
A problem is a world. A state is one place in that world. A move takes you to another place. A stop condition says when a path is done. An answer type says what comes back.
I am here.
I know these facts.
These moves are legal.
This move changes the state.
When I stop, I return or record this kind of answer.
Visual:
The beginner question is always:
What is the world?
Where am I standing?
Where can I move next?
What do I remember?
What happens when I stop?
1) Matrix / grid world
problem: explore land cells, find a path, count a region, search a word
c0 c1 c2 c3
+----+----+----+----+
r0 | . | # | . | . |
+----+----+----+----+
r1 | . | S | . | . |
+----+----+----+----+
r2 | . | . | # | . |
+----+----+----+----+
state = current cell = (r1, c1)
possible next states:
(r0,c1) blocked
^
|
(r1,c0) <--- (r1,c1) ---> (r1,c2)
|
v
(r2,c1)
memory can be:
visited cells, current path, distance layer, remaining keys, current word index
classification:
mark and move only -> pure explorer / flood fill
need shortest path -> BFS explorer
need choose letters in path -> backtracking explorer
same cell plus extra facts -> richer state, such as (r,c,keys) or (r,c,wordIndex)
2) Tree world
problem: traverse, compute depth, find diameter, collect paths
A
/ | \
B C D
/ \
E F
state = current node = B
possible next states:
parent A
^
|
B
/ \
E F
If the tree is rooted and you only move downward:
B -> E
B -> F
If the problem treats the tree like an undirected graph:
B -> A
B -> E
B -> F
classification:
visit nodes and mark/collect -> traversal explorer
return height/count/best upward -> tree summary recursion
split left/right and rebuild value -> divide/recombine style
3) String index world
problem: decode, segment, match, partition, scan
string:
s = "leetcode"
0 1 2 3 4 5 6 7 8
l e e t c o d e
^
state i=0
possible next states in Word Break:
i=0
|
| take "leet"
v
i=4
|
| take "code"
v
i=8 stop
state = index i
move = choose a valid word/piece starting at i
stop = i == len(s)
memory = memo[i] if the same index repeats
classification:
single pass with reusable border/hash -> string structure
choose substrings and undo -> backtracking
same index repeats -> DP explorer
4) Choice / path world
problem: subsets, permutations, partitions, N-Queens
nums = [2, 7, 9]
state = (index, current_path)
(i=0, path=[])
/ \
skip 2 take 2
/ \
(i=1, []) (i=1, [2])
/ \ / \
skip 7 take 7 skip 7 take 7
| | | |
(i=2, []) (i=2,[7]) (i=2,[2]) (i=2,[2,7])
move = choose one legal branch
undo = remove the choice before trying the next branch
stop = index == len(nums)
answer = record the current path, or count valid paths
classification:
concrete path/output matters -> choice explorer / backtracking
only best count/value matters -> often DP after compressing the state
5) Two-index DP world
problem: LCS, edit distance, interleaving string, distinct subsequences
state = one cell in an index grid = (i, j)
text2 index j
0 1 2
+-----+-----+-----+
i=0 |0,0 |0,1 |0,2 |
+-----+-----+-----+
i=1 |1,0 |1,1 |1,2 |
+-----+-----+-----+
i=2 |2,0 |2,1 |2,2 |
+-----+-----+-----+
^
|
current state could be (2,1)
possible next states depend on the recurrence:
LCS:
if chars match: (i,j) -> (i+1,j+1)
if chars differ: (i,j) -> (i+1,j) and (i,j+1)
Edit distance:
insert: (i,j) -> (i,j+1)
delete: (i,j) -> (i+1,j)
replace/match: (i,j) -> (i+1,j+1)
memory = dp[i][j]
stop = one index reaches the end
answer = value returned for this pair of suffixes/prefixes
classification:
same (i,j) repeats and returns a value -> DP explorer
moving through characters is the world -> string state explorer
The shared picture:
problem world -> current state -> legal next states -> stop/return
What changes between families is what "return" means:
pure explorer: mark and move
choice explorer: record a completed path
DP explorer: return cached answer for this state
BFS explorer: return shortest layer distance
string explorer: move through index/pair/path/match state
recombine: return child summary to parent
For divide/recombine, the wording changes:
I own this unit.
This is the smallest direct answer.
I split into these child units.
Each child returns this summary.
I combine summaries into my own summary.
Same recursion. Different emphasis.
Superset Family Map
State Space Exploration Superset
|
|-- Pure Explorer
| |-- flood fill
| |-- graph component traversal
| |-- simple tree traversal
| |-- reachability marking
|
|-- Choice Explorer
| |-- subsets
| |-- permutations
| |-- combinations
| |-- partitioning
| |-- generated valid objects
|
|-- Constraint Explorer
| |-- N-Queens
| |-- Sudoku
| |-- matchsticks to square
| |-- k equal subset partitioning
|
|-- DP Explorer
| |-- index DP
| |-- capacity DP
| |-- amount DP
| |-- two-string DP
| |-- interval DP
| |-- bitmask DP
|
|-- BFS Explorer
| |-- shortest equal-cost moves
| |-- multi-source time layers
| |-- state with extra carried facts
|
|-- String State Explorer
| |-- index state
| |-- pair state
| |-- path state
| |-- center/radius state
| |-- interval state
| |-- trie node state
| |-- automaton state
| |-- rolling window state
|
|-- Tree Summary Bridge
| |-- maximum depth
| |-- diameter
| |-- LCA
| |-- validate BST with carried bounds
|
`-- Divide/Recombine Special Case
|-- merge sort
|-- count inversions
|-- maximum subarray by summaries
|-- tree construction
|-- serialization and deserialization
|-- segment tree
|-- recursive parsing
High-Level Comparison
| Family | Main question | Main state/unit | Main return shape | Typical engine |
|---|---|---|---|---|
| Pure explorer | What can I reach? | node, cell, frontier item | mark, count, boolean | DFS/BFS traversal |
| Choice explorer | What can I build? | index plus path | recorded constructions | backtracking |
| Constraint explorer | Which choices stay legal? | variable plus trackers | valid construction or decision | pruned backtracking |
| DP explorer | Does this future repeat? | memo key | count, boolean, min, max | memo/table |
| BFS explorer | What is shortest with equal-cost moves? | queue state | distance | BFS layers |
| String state explorer | Where am I in the string relation? | index, pair, center, trie node, automaton | count, best, match, decision | DP, backtracking, automaton, hashing |
| Tree summary bridge | What should child calls return upward? | node plus carried facts | simple summary or flags | tree DFS |
| Divide/recombine | What child summaries rebuild the parent? | range, subtree, token range, segment | same-type summary | split/solve/combine |
Core Mental Model
Every problem in this superset can be described with five questions.
1. Where am I?
2. What information am I carrying?
3. What moves, choices, or splits are legal now?
4. Where does each move lead?
5. What do I record, return, or combine when this call finishes?
If those questions are clear, code is usually mechanical. If those questions are vague, code usually becomes a mixture of guesses.
Universal recursive exploration:
solve(state):
if terminal(state):
return answer_from(state)
result = neutral_value
for move in legal_moves(state):
next_state = transition(state, move)
child_answer = solve(next_state)
result = combine(result, child_answer)
return result
Universal pure traversal:
visit(state):
if invalid(state) or seen(state):
return
mark(state)
for next_state in neighbors(state):
visit(next_state)
Universal backtracking:
search(state, path):
if complete(state):
record copy(path)
return
for choice in legal_choices(state):
apply choice
search(next_state, path)
undo choice
Universal DP:
answer(state):
if base case:
return base value
if state in memo:
return memo[state]
memo[state] = combine answers from next states
return memo[state]
Universal BFS:
queue = [start_state]
seen = {start_state}
while queue:
state, distance = pop_front(queue)
if target(state):
return distance
for next_state in legal_neighbors(state):
if next_state not in seen:
seen.add(next_state)
push(next_state, distance + 1)
Universal divide/recombine:
solve(unit):
if unit is base case:
return base summary
child_units = split(unit)
child_summaries = [solve(child) for child in child_units]
cross_summary = compute_cross_work_if_needed(child_summaries)
return combine(child_summaries, cross_summary)
State vs Unit Translation Wall
The state-space wording and divide/recombine wording are two views of the same recursive skeleton.
| State Space word | Divide/Recombine word | Intuition |
|---|---|---|
| state | unit | the call owns a configuration or a range-like piece |
| choice | split | the call decides a move or divides into child pieces |
| transition | child call | the call advances or delegates to smaller pieces |
| stop condition | base case | the call knows when direct answer is possible |
| answer from state | child summary | the child returns what the parent needs |
| combine child answers | recombine | the parent rebuilds its own answer |
| visited/memo | summary/index/cache | remembered information prevents repeated work |
Visual:
State exploration:
state A --move--> state B --move--> state C
| | |
mark/record/cache mark/cache stop
Divide/recombine:
parent summary
/ \
left child summary right child summary
/ \
base unit base unit
Moving Forward vs Rebuilding Upward
This is the most useful boundary.
If the main work happens while moving forward, use exploration.
If the main work happens when child answers return, use recombine.
Forward work:
flood_fill(cell):
mark cell
move to neighbors
Upward work:
count_inversions(range):
solve left half
solve right half
count cross pairs while merging
return sorted range and count
Middle work:
diameter(node):
ask children for height
update best path through current node
return height
Diameter is not pure marking. It is also not the same as full merge counting. It is a tree summary bridge.
How To Translate Any Problem
Translate in this order.
Step 1: Identify The Goal
Ask:
What must I return?
Common answer types:
| Goal | Usually means |
|---|---|
| all objects | backtracking |
| one valid object | search with early stop |
| count | DP or combinational backtracking |
| minimum/maximum | DP, BFS, or ordered optimization |
| shortest equal-cost moves | BFS |
| reachability/components | pure traversal |
| rebuilt structure | divide/recombine |
| string match positions | string traversal or automaton |
Step 2: Decide What One Call Owns
A call may own:
index
path
row, col
node
node plus bounds
amount
capacity
i, j
left, right
mask
trie_node
automaton_state
range [lo, hi]
token interval
segment-tree interval
The owned object determines the rest.
Step 3: Remove What Does Not Belong
State should be complete but minimal.
Complete:
contains every fact that changes future choices or answers
Minimal:
does not include facts already derivable from the state
Wrong DP key:
(index, remaining, path)
Right DP key:
(index, remaining)
because the best future does not depend on the concrete path.
Step 4: Find Moves, Choices, Or Splits
Move examples:
grid:
up, down, left, right
lock:
rotate one wheel up or down
string index:
consume one character, two digits, or one dictionary word
two-string DP:
match both, skip first, skip second, edit
tree:
visit left child, visit right child
divide/recombine:
split range, split traversal arrays, split at operator
Step 5: Find Stop Or Base Cases
Stop examples:
index == n
remaining == 0
node is None
out of bounds
visited already
target reached
range is empty
range has one item
token is a number
Write stops before writing recursive calls.
Step 6: Define Return Shape
Return shape decides the family.
| Return shape | Family |
|---|---|
| nothing, mark only | pure explorer |
| completed path | backtracking |
| count / boolean / min / max from state | DP explorer |
| distance | BFS explorer |
| child height / flags | tree summary bridge |
| sorted half / segment aggregate / subtree root | divide/recombine |
| border, hash, trie node, automaton state | string structure |
Step 7: Choose Engine
Use this quick guide:
Need all valid paths or constructions?
-> backtracking
Need to mark reachable nodes/cells?
-> pure DFS/BFS traversal
Need shortest equal-cost path?
-> BFS
Can the same state repeat?
-> DP
Does a small set belong in the state?
-> bitmask
Does parent need child summaries?
-> tree summary or divide/recombine
Does string progress or mismatch memory dominate?
-> string state / string structure
Pure Explorer / Tail-Recursion-Like Traversal
Pure explorers mostly move and mark.
Use when:
- the goal is reachability
- the goal is connected component marking
- each state is processed once
- child calls do not return rich summaries
- traversal side effects are enough
Examples:
Number of Islands
Flood Fill
Max Area of Island
Clone Graph
Pacific Atlantic Water Flow
simple tree preorder/inorder/postorder traversal
Tail-recursion-like intuition:
dfs(cell):
mark cell
continue to neighbors
This feels tail-recursive because the call mostly pushes exploration forward. But multi-neighbor DFS is not strict compiler tail recursion. The practical point is:
No sibling result needs a rich recombine step.
Pure explorer checklist:
What is the current node/cell?
What makes it invalid?
What marks it as processed?
What neighbors are legal?
Can I process each state once?
What does the traversal leave behind?
Choice Explorer
Choice explorers build concrete objects.
Use when:
- the output asks for all combinations, permutations, partitions, boards, or paths
- a partial answer is being built
- choices must be tried one by one
- sibling branches must not share mutations
Core idea:
choose
recurse
undo
Examples:
Subsets
Permutations
Combination Sum
Generate Parentheses
Restore IP Addresses
Palindrome Partitioning
Word Search
Backtracking skeleton:
path = []
search(state):
if complete:
answers.add(copy(path))
return
for choice in legal_choices(state):
apply choice
search(next_state)
undo choice
The important rule:
Only copy the path when recording an answer.
Constraint Explorer
Constraint explorers are choice explorers with fast legality memory.
Use when:
- many choices are illegal
- legality is based on repeated facts
- checking the whole board/path every time is too slow
Examples:
N-Queens:
columns
row - col diagonals
row + col diagonals
Sudoku:
row digit masks
column digit masks
box digit masks
Permutations with duplicates:
used indexes
duplicate sibling skip rule
Constraint skeleton:
choose next variable
for candidate in candidates:
if candidate violates tracker:
continue
apply candidate
update tracker
search(next state)
restore tracker
undo candidate
The undo should mirror the mutation order.
Bitmask State
A bitmask stores a small set inside an integer.
Use when:
- the number of items is small
- each item has a stable index
- you need cheap copy, membership, hashing, or visited keys
Examples:
used indexes in permutations
visited nodes in shortest path visiting all nodes
collected keys in a grid
selected skills in smallest sufficient team
available digits in Sudoku
Operations:
bit = 1 << i
contains i:
mask & bit
add i:
mask | bit
remove i:
mask & ~bit
all n items:
mask == (1 << n) - 1
Visual:
items: A B C D
index: 0 1 2 3
mask: 1 0 1 0
set = {A, C}
Bitmask is not an algorithm family by itself. It is a representation used by backtracking, DP, and BFS.
DP Explorer
DP explorers ask:
What is the answer from this state?
Use when:
- the same state can be reached more than once
- the answer from that state is deterministic
- the output is count, boolean, minimum, maximum, or score
Top-down DP:
write recursive answer(state)
memoize by the full state key
reuse answer when state repeats
Bottom-up DP:
choose an order where dependencies are already known
fill a table
return target cell
Top-down template:
from functools import lru_cache
def solve_problem(data):
@lru_cache(None)
def solve(state):
if base_case(state):
return base_value
ans = neutral_value
for next_state in next_states(state):
ans = combine(ans, solve(next_state))
return ans
return solve(start_state)
Key rule:
The memo key must include every variable that changes the future answer.
BFS Explorer
BFS explorers ask:
What is the shortest equal-cost path to a target state?
Use when:
- every move has the same cost
- target can be recognized
- shortest number of moves is required
- state space is bounded or can be pruned
Examples:
Open the Lock
Word Ladder
Minimum Genetic Mutation
Sliding Puzzle
Rotting Oranges
Shortest Path Visiting All Nodes
Shortest Path in Grid With Obstacles Elimination
Visited timing:
mark visited when pushing into the queue
Why:
the first time a state is pushed, it has already been reached by the shortest layer
If edge costs differ, use weighted shortest-path logic instead of plain BFS.
String State Explorer
String problems are still state exploration when the main question is:
Where am I in the string relation, and what character/index move is legal?
State shapes:
| Shape | Meaning | Examples |
|---|---|---|
index | position in one string | Decode Ways, Word Break, Restore IP |
(i, j) | positions in two strings | LCS, Edit Distance, Distinct Subsequences |
(row, col, k) | grid path plus word index | Word Search |
(trie_node, index/path) | dictionary prefix state | Word Search II, Trie search |
(center, radius) | palindrome expansion | Longest Palindromic Substring |
(l, r) | interval | Longest Palindromic Subsequence, parsing |
| automaton state | reusable match progress | KMP, Aho-Corasick |
| fixed window | current substring | Repeated DNA, rolling hash |
String state cards:
Decode Ways:
state = index
move = decode one or two valid digits
stop = index == len(s)
return = number of ways
shape = string-index DP
Word Break:
state = index
move = consume one dictionary word
stop = index == len(s)
return = possible/count
shape = string-index DP
Restore IP Addresses:
state = index, parts, path
move = choose next valid segment
stop = consumed string and built four parts
return = completed addresses
shape = string choice explorer
Palindrome Partitioning:
state = index, path
move = choose palindromic prefix
stop = index == len(s)
return = completed partitions
shape = string choice explorer
Word Search:
state = row, col, word_index, visited cells
move = move to matching neighbor
stop = word complete or invalid path
return = found/not found
shape = path explorer with undo
Word Search II:
state = row, col, trie_node, visited cells
move = follow trie edge through neighboring cell
stop = terminal word or dead prefix
return = found words
shape = path explorer plus trie memory
LCS:
state = (i, j)
move = match both or advance one string
stop = one string exhausted
return = best length
shape = two-string DP
Edit Distance:
state = (i, j)
move = match, insert, delete, replace
stop = one string exhausted
return = minimum edits
shape = two-string DP
KMP:
state = text index, pattern index
move = match forward or fallback by border table
stop = pattern matched or text exhausted
return = match positions
shape = automaton-like traversal
String rule:
Classify the string state shape before naming the algorithm.
Tree Summary Bridge
Tree problems often sit between pure traversal and recombine.
Simple traversal:
preorder(node):
visit node
preorder(left)
preorder(right)
Simple returned summary:
height(node):
return 1 + max(height(left), height(right))
Bridge summary:
diameter(node):
left_height = height(left)
right_height = height(right)
best = max(best, left_height + right_height)
return 1 + max(left_height, right_height)
True divide/recombine:
build_tree(pre_range, in_range):
root = preorder first
split inorder around root
root.left = build(left ranges)
root.right = build(right ranges)
return root
Boundary:
Traversal:
moving through existing structure
Tree summary:
moving through existing structure and returning small facts
Tree construction:
rebuilding a new structure from split evidence
Divide/Recombine Special Case
Use divide/recombine when:
- one call owns a unit
- the unit can be split
- children return summaries
- parent needs those summaries
- cross-boundary work may be necessary
- parent returns the same kind of summary upward
Core questions:
What is the unit?
What is the base case?
How does it split?
What does each child return?
What cross-boundary work exists?
How does the parent combine?
Does the parent return the same summary type?
Examples:
Maximum Subarray:
summary = total sum, best prefix, best suffix, best subarray
cross = left suffix + right prefix
Count Inversions:
summary = sorted values plus count
cross = left values greater than right values
Build Tree:
summary = subtree root
split = root position in inorder traversal
Segment Tree:
summary = interval aggregate
split = midpoint
Recursive Parsing:
summary = possible values or parsed node
split = operator or grammar boundary
Unified Translation Table
| Problem | Lens | State / unit | Move / choice / split | Stop / base case | Return / memory / combine | Execution shape | Why this classification |
|---|---|---|---|---|---|---|---|
| Subsets | Choice explorer | index, path | take or skip | index == n | record path | backtracking | concrete construction paths are output |
| Subsets II | Choice explorer | index, path, duplicate rule | take or skip unique choice | index == n | record path | duplicate-pruned backtracking | sibling duplicate choices must be skipped |
| Permutations | Choice explorer | path, used | choose unused item | len(path) == n | record path | backtracking | order of chosen items matters |
| Generate Parentheses | Constraint explorer | opened, closed, path | add open or legal close | full length | record path | constraint backtracking | legality constraints define choices |
| Combination Sum | Choice explorer | start, remaining, path | pick candidate | remaining == 0 | record path | backtracking | choices build combinations |
| Restore IP Addresses | String choice explorer | index, parts, path | choose next segment | consumed string and four parts | record address | backtracking | string index advances by segment |
| Palindrome Partitioning | String choice explorer | index, path | choose palindromic prefix | index == n | record partition | backtracking | each move consumes one valid substring |
| Word Search | String path explorer | row, col, word_index, visited cells | move to matching neighbor | word complete or invalid | boolean | DFS backtracking | grid path plus word index is state |
| Maximum Depth of Binary Tree | Tree traversal | node | visit children | node is None | height | tree DFS | simple returned summary |
| Diameter of Binary Tree | Tree summary bridge | node | ask child heights | node is None | height plus global/bundled best | tree DFS summary | child summaries combine through current node |
| Validate BST | Tree traversal with carried constraints | node, low, high | validate children with tighter bounds | null or invalid | boolean | tree DFS | carried bounds are state |
| Lowest Common Ancestor | Tree traversal with return flags | node | search left and right | target or null | node/flags | tree DFS | child returns determine ancestor |
| Clone Graph | Pure explorer | original node, clone map | visit neighbors | already cloned | clone reference | DFS/BFS with map | clone map is visited memory |
| Number of Islands | Pure explorer | row, col | visit adjacent land | boundary/water/visited | mark component | flood fill | moving and marking is the main work |
| Max Area of Island | Pure explorer with count | row, col | visit adjacent land | boundary/water/visited | count | flood fill | count is simple accumulation |
| Pacific Atlantic Water Flow | Pure multi-source explorer | row, col, ocean side | reverse-flow neighbors | no new cells | reachable sets | DFS/BFS | reachability is the goal |
| Course Schedule | Frontier explorer | zero-indegree frontier | process available course | all processed or stuck | validity | topological BFS | frontier models released states |
| Is Graph Bipartite | Pure explorer with labels | node, color map | color neighbors | conflict or done | validity | DFS/BFS coloring | labels prove structure consistency |
| N-Queens | Constraint explorer | row, board, trackers | place safe queen | row == n | board | constraint backtracking | trackers make legality fast |
| Sudoku | Constraint explorer | board, empty cell, trackers | legal digit | board filled | solved board | constraint search | choice legality dominates |
| Matchsticks to Square | Constraint explorer | index, side lengths | place stick on a side | all sticks placed | boolean | backtracking | side lengths are carried state |
| Partition to K Equal Sum Subsets | Choice + bitmask | mask, bucket_sum, buckets_done | add unused number | all buckets filled | boolean | bitmask backtracking | mask represents chosen set |
| House Robber | DP explorer | index | rob or skip | past end | best value | DP | suffix answer repeats |
| House Robber II | DP explorer | index, linear case | rob or skip | range exhausted | best value | DP over cases | circle becomes two ranges |
| 0/1 Knapsack | DP explorer | index, capacity | take or skip | no items | best value | DP | repeated item/capacity states |
| Target Sum | DP explorer | index, sum | add or subtract | no numbers | count | DP/backtracking | repeated sums can be cached |
| Coin Change Minimum | DP explorer | amount | choose coin | amount zero | minimum coins | DP | amount states repeat |
| Coin Change Count | DP explorer | coin index, remaining | use or skip coin | remaining zero | count | DP | state controls combination order |
| Decode Ways | String index DP | index | consume one/two digits | end of string | count | DP | suffix answer depends on index |
| Word Break | String index DP | index | consume dictionary word | end of string | boolean/count | memo DFS/DP | suffix answer repeats |
| Longest Common Subsequence | Two-string DP | i, j | match or advance | one string exhausted | best length | DP | suffix pair determines answer |
| Edit Distance | Two-string DP | i, j | insert/delete/replace/match | one string exhausted | minimum edits | DP | alignment state repeats |
| Distinct Subsequences | Two-string DP counting | i, j | skip source or match target | target consumed/source exhausted | count | DP | counts paths through alignment states |
| Interleaving String | Two-string DP | i, j | take char from first/second | target consumed | boolean | DP | target index is derived |
| Unique Paths With Obstacles | Grid DP explorer | row, col | move right or down | destination reached or blocked | count | DP | paths to cells overlap |
| Longest Increasing Path in Matrix | Grid DP explorer | row, col | move to larger neighbor | no larger neighbor | longest length | DFS plus memo | each cell’s best future repeats |
| Longest Palindromic Subsequence | Interval DP | l, r | match ends or shrink | empty/single | best length | DP | interval answer repeats |
| Longest Palindromic Substring | Center traversal | center, radius | expand mirrors | mismatch/boundary | best interval | palindrome traversal | moves outward from center |
| Palindromic Substrings | Center traversal | center, radius | expand mirrors | mismatch/boundary | count | palindrome traversal | every center explores valid radii |
| Word Ladder | String BFS | word | mutate one character | target word | distance | BFS | equal-cost word moves |
| Minimum Genetic Mutation | String BFS | gene | mutate one character | target gene | distance | BFS | equal-cost mutations |
| Open the Lock | BFS explorer | code | rotate wheel | target code | distance | BFS | equal-cost transitions |
| Sliding Puzzle | BFS explorer | board encoding | swap blank | target board | distance | BFS | board is compact state |
| Rotting Oranges | Multi-source BFS | rotten cells by minute | rot neighbor | no fresh oranges | minutes | BFS layers | layers model time |
| Shortest Path in Grid With Obstacles Elimination | BFS with carried state | row, col, breaks | move to neighbor | destination | distance | BFS | breaks change future reachability |
| All Keys Grid | BFS + bitmask | row, col, key mask | move/collect key | all keys | distance | BFS bitmask | key set belongs in visited state |
| Shortest Path Visiting All Nodes | BFS + bitmask | node, visited mask | move to neighbor | all visited | distance | BFS bitmask | visited set changes state |
| Smallest Sufficient Team | Bitmask DP | person index, skills mask | take or skip person | all skills | minimum team | DP | skills mask summarizes coverage |
| Maximum Score After N Operations | Bitmask DP | used mask, operation | pair unused numbers | all paired | maximum score | DP | used set determines future |
| Maximum Subarray Divide-Conquer | Divide/recombine | array range | split halves | one item | four-value summary | divide and conquer | crossing answer needs summaries |
| Merge Sort | Divide/recombine | array range | split halves | one item | sorted range | divide and conquer | child sorted lists merge upward |
| Count Inversions | Divide/recombine | sorted range | split halves | one item | sorted values plus count | merge counting | cross pairs require sorted children |
| Reverse Pairs | Divide/recombine | sorted range | split halves | one item | sorted values plus count | merge counting | cross pair count is upward work |
| Count of Smaller After Self | Divide/recombine | index range | split halves | one item | sorted indexes and counts | merge counting | right-smaller counts happen at merge |
| Kth Largest Element | Ordered selection | partition range | pivot partition | pivot rank target | selected value | quickselect | partition discards one side |
| Median of Unsorted Array | Ordered selection | partition range | pivot partition | middle rank found | selected value | quickselect | same partition logic selects median rank |
| Build Tree From Preorder/Inorder | Divide/recombine | traversal ranges | root splits inorder | empty range | subtree root | tree construction | children return rebuilt subtrees |
| Build Tree From Inorder/Postorder | Divide/recombine | traversal ranges | root splits inorder | empty range | subtree root | tree construction | postorder root defines the split and child ranges |
| Serialize Binary Tree | Recursive codec | node | encode node/children | null | token stream | recursive encoding | structure flows through recursive order |
| Deserialize Binary Tree | Recursive codec | token stream index | consume root/children | null token | subtree root | recursive decoding | child calls rebuild structure |
| Range Sum Query Mutable | Range recombine | interval node | split by midpoint | exact cover | aggregate | segment tree | query combines covered nodes |
| Range Minimum Query | Range recombine | interval node | split by midpoint | exact cover | aggregate | segment tree | same summary type flows upward |
| Different Ways to Add Parentheses | String interval recombine | token interval | split at operator | number token | all values | recursive parsing | operator combines child values |
| Basic Calculator | Grammar recombine | expression unit | parse grammar pieces | atomic token | value | recursive parsing | grammar defines split and combine |
| Decode String | Grammar recombine | bracketed range | parse child ranges | literal/closing bracket | expanded string | recursive parsing | child expansions concatenate/repeat |
| Find First Occurrence | String automaton | text index, pattern index | match or fallback | full pattern/text end | match index | KMP | border memory avoids restart |
| Repeated Substring Pattern | String structure | prefix/suffix border | compute border | pattern processed | repeated-unit decision | KMP | border defines reusable period |
| Shortest Palindrome | String structure | prefix palindrome border | KMP over combined string | scan complete | prefix length | KMP | border finds longest palindromic prefix |
| Sum of Scores of Built Strings | String structure | prefix match length | reuse Z-box | scan complete | score sum | Z algorithm | Z-box stores prefix matches |
| Repeated DNA Sequences | String window | fixed window | slide one char | all windows scanned | repeated windows | rolling hash | window state moves forward |
| Longest Duplicate Substring | String + ordered search | length and window | binary search length, hash windows | length boundary | duplicate substring | rolling hash | length order plus hash memory |
| Implement Trie | String structure | trie node | follow/create edge | word consumed | prefix path memory | trie | path represents prefix state |
| Word Search II | String path + trie | grid cell and trie node | follow trie edge in grid | terminal/dead prefix | found words | trie backtracking | grid path and prefix memory combine |
| Aho-Corasick Search | Automaton traversal | automaton node | consume char/failure link | text exhausted | emitted matches | multi-pattern automaton | node stores reusable prefix state |
| Suffix Array Search | String structure | suffix rank/range | compare suffixes | search complete | match/range | suffix indexing | sorted suffix order is memory |
Canonical Examples
Example: Subsets
State:
index, path
Choices:
skip nums[index]
take nums[index]
Stop:
index == len(nums)
Answer:
record copy(path)
Why:
The path itself is the output, so this is choice exploration.
Example: N-Queens
State:
row, path, occupied_columns, occupied_diag1, occupied_diag2
Choices:
place queen in any safe column of current row
Trackers:
column
row - col diagonal
row + col diagonal
Why:
The board is built by choices, but fast legality trackers make the search practical.
Example: House Robber
State:
index
Recurrence:
best(index) = max(best(index + 1), nums[index] + best(index + 2))
Why:
Once index is known, the best future is fixed.
Example: Word Break
State:
index
Moves:
consume any dictionary word that starts at index
Why:
This is string-index DP, not substring brute force.
Example: LCS
State:
i, j
Moves:
if a[i] == b[j]:
move to i + 1, j + 1
else:
move to i + 1, j
move to i, j + 1
Why:
The suffix pair determines the answer.
Example: Number of Islands
State:
row, col
Move:
move to adjacent land cell
Why:
This is pure exploration. Marking reachable land is the work.
Example: Diameter of Binary Tree
State:
node
Return:
height of subtree
Side update:
best diameter through current node
Why:
This is a tree summary bridge. Child heights are recombined through the node.
Example: Build Tree From Traversals
Unit:
preorder range, inorder range
Split:
root value splits inorder range into left and right subtree ranges
Return:
subtree root
Why:
This is true divide/recombine because child calls rebuild child subtrees.
Example: Count Inversions
Unit:
array range
Child summary:
sorted values plus inversion count
Cross work:
count left values greater than right values during merge
Why:
The sorted child summaries are necessary for the parent answer.
Example: KMP Search
State:
text index, pattern index
Memory:
border table
Move:
match advances both indexes
mismatch follows fallback border
Why:
This is automaton-like string traversal with reusable mismatch memory.
Dry Runs
Dry Run: Flood Fill As Pure Explorer
Grid:
1 1 0
1 0 1
0 1 1
Start:
(0, 0)
Trace:
visit (0,0)
mark it
move to (0,1)
mark it
move to (1,0)
mark it
Invariant:
every marked cell belongs to the current component
Verdict:
pure explorer
No child returns a rich summary to combine.
Dry Run: Word Search With Undo
Board:
A B C
D E F
Word:
ABE
Trace:
A matches index 0
mark A
move to B
B matches index 1
mark B
move to E
E matches index 2
word complete
Undo:
when a branch fails:
unmark the cell before trying the next neighbor
Invariant:
visited cells are exactly the current word-prefix path
Verdict:
path explorer with undo
Dry Run: Subsets
Input:
[1, 2]
Tree:
dfs(0), path=[]
|-- skip 1
| `-- dfs(1), path=[]
| |-- skip 2 -> []
| `-- take 2 -> [2]
`-- take 1
`-- dfs(1), path=[1]
|-- skip 2 -> [1]
`-- take 2 -> [1, 2]
Verdict:
choice explorer
Dry Run: Word Break
String:
leetcode
Dictionary:
leet, code
Moves:
index 0 --leet--> index 4
index 4 --code--> index 8
Return:
can_break(8) = true
can_break(4) = true
can_break(0) = true
Invariant:
can_break(i) answers whether suffix s[i:] can be segmented
Verdict:
string-index DP
Dry Run: LCS
Strings:
a = abc
b = ac
Trace:
lcs(0,0): a == a
1 + lcs(1,1)
lcs(1,1): b != c
max(lcs(2,1), lcs(1,2))
lcs(2,1): c == c
1 + lcs(3,2)
Invariant:
lcs(i, j) is the best LCS length of a[i:] and b[j:]
Verdict:
two-string DP
Dry Run: Maximum Depth
Tree:
1
/ \
2 3
/
4
Return flow:
depth(4) = 1
depth(2) = 2
depth(3) = 1
depth(1) = 3
Verdict:
tree traversal with simple summary
Dry Run: Diameter
Tree:
1
/ \
2 3
/ \
4 5
At node 2:
left_height = 1
right_height = 1
through_2 = 2
return height = 2
At node 1:
left_height = 2
right_height = 1
through_1 = 3
return height = 3
Verdict:
tree summary bridge
Dry Run: Build Tree From Traversals
Input:
preorder = [3, 9, 20, 15, 7]
inorder = [9, 3, 15, 20, 7]
Step:
root = 3
left inorder = [9]
right inorder = [15, 20, 7]
Contract:
build(pre_range, in_range) returns subtree root
Verdict:
true divide/recombine
Dry Run: Count Inversions
Input:
[2, 1, 3]
Split:
[2] and [1, 3]
Merge:
compare 2 and 1:
1 is smaller
inversion count += 1
Return:
sorted range = [1, 2, 3]
count = 1
Verdict:
true divide/recombine with cross-boundary work
Dry Run: Segment Tree Query
Query:
sum [2, 6]
Tree:
[0,7]
/ \
[0,3] [4,7]
/ \ / \
[0,1][2,3] [4,5][6,7]
Covered pieces:
[2,3] + [4,5] + [6,6]
Verdict:
range recombine
Dry Run: KMP Fallback
Pattern:
ababac
Text prefix:
ababax
At mismatch:
matched = ababa
fallback border = aba
Meaning:
Do not restart from zero.
Reuse the largest prefix that is also a suffix.
Verdict:
string automaton traversal
Dry Run: Palindrome Center
String:
ababa
Center:
index 2
Expansion:
left=1, right=3 -> b == b
left=0, right=4 -> a == a
left=-1, right=5 -> stop
Verdict:
string center traversal
Wrong Classification Mini Cases
Number of Islands
Wrong:
divide/recombine
Better:
pure explorer
Reason:
The child calls mark land. Parent does not need child summaries to rebuild an answer.
Count Inversions
Wrong:
simple exploration
Better:
divide/recombine
Reason:
The parent needs sorted child summaries to count cross pairs.
Word Search
Wrong:
string matching first
Better:
state exploration first
Reason:
The hard part is grid path plus visited cells.
Word Break
Wrong:
substring brute force
Better:
string-index DP
Reason:
Once index is known, the suffix answer is fixed.
Build Tree
Wrong:
ordinary traversal
Better:
divide/recombine
Reason:
The call owns traversal ranges, splits them, and returns a subtree root.
Diameter
Wrong:
pure traversal only
Better:
tree summary bridge
Reason:
The traversal is simple, but child heights are combined through the current node.
Longest Duplicate Substring
Wrong:
plain DP
Better:
string structure plus ordered search
Reason:
The useful memory is substring equality by hash/suffix structure, and length is searched.
Decision Rules
Fast Pattern Choice
Does it ask for all concrete constructions?
yes -> choice explorer / backtracking
Does it mainly mark reachable nodes/cells?
yes -> pure explorer
Does it ask for shortest equal-cost moves?
yes -> BFS explorer
Can multiple paths reach the same future state?
yes -> DP explorer
Does the state include a small set?
yes -> bitmask representation may help
Is the primary state string index/pair/path/center/interval/automaton?
yes -> string state explorer, then choose engine
Does parent need child summaries?
yes -> tree summary bridge or divide/recombine
Is there cross-boundary work?
yes -> true divide/recombine
Backtracking Or DP
Choose backtracking when:
- concrete paths are output
- all valid constructions are needed
- path mutation must be undone
Choose DP when:
- output is count, boolean, min, or max
- repeated states exist
- prior path does not change the future answer
Question:
If two different paths reach this same state, is the future answer identical?
If yes, use DP.
DFS Or BFS
Choose BFS when:
- every move has equal cost
- shortest distance is required
- target state can be recognized
Choose DFS/backtracking when:
- enumeration is needed
- a full construction must be explored
- shortest distance is not the main output
Traversal Or Recombine
Choose traversal when:
the call mostly moves, marks, or checks
Choose recombine when:
the parent cannot answer without child summaries
Ask:
What does the child return that the parent cannot compute otherwise?
If the answer is nothing substantial, it is probably exploration.
Common Failure Modes
Incomplete State
Symptom:
valid paths are rejected or invalid paths are accepted
Cause:
state misses a fact that changes future moves
Examples:
wrong:
(row, col)
right for key grid:
(row, col, keys_mask)
wrong:
word index omitted from Word Search
right:
row, col, word_index, visited cells
Oversized State
Symptom:
memo rarely hits
Cause:
state includes irrelevant history
Fix:
remove fields that do not change the future answer
Missing Undo
Symptom:
sibling branches contain choices from earlier branches
Fix:
mutate
recurse
undo
Wrong BFS Visited Timing
Symptom:
queue grows with duplicate states
Fix:
mark visited when pushing, not when popping
Wrong Engine For Weighted Moves
Symptom:
BFS returns fewer edges but higher total cost
Fix:
use weighted shortest path logic
Calling Everything Divide/Recombine
Symptom:
you invent a combine step, but child calls only mark visited states
Fix:
use pure exploration
Calling Everything Traversal
Symptom:
the parent needs child facts but the helper does not return enough information
Fix:
define the child summary contract
Missing Cross-Boundary Work
Symptom:
left and right answers are correct but parent answer is too small
Examples:
maximum subarray:
forgot left suffix + right prefix
count inversions:
forgot cross pairs
Wrong String Classification
Symptom:
too much string machinery or too much brute force
Fix:
name the string state first:
index, pair, path, center, interval, trie node, automaton, or window
Performance Notes
Start with correctness. Then optimize in this order:
1. Choose the right execution family.
2. Make the state complete.
3. Make the state minimal.
4. Prune illegal branches early.
5. Memoize repeated states.
6. Use bitmasks for small sets.
7. Encode BFS states compactly.
8. Use arrays for dense DP.
9. Use child summaries to avoid recomputing cross work.
Pure Explorer Performance
Useful improvements:
- mark before recursing
- avoid revisiting states
- encode grid positions as integers when large
- use iterative stack/queue if recursion depth is risky
- reuse direction arrays
Backtracking Performance
Useful improvements:
- mutate one path
- copy only complete answers
- prune before recursion
- sort candidates when it enables early break
- skip duplicate sibling choices
- use bitmasks or boolean arrays for used sets
Constraint Search Performance
Useful improvements:
- maintain O(1) legality trackers
- choose the most constrained variable first
- undo trackers in reverse order
- precompute candidate sets when stable
DP Performance
Useful improvements:
- use tuple keys only for complete states
- compress dimensions when recurrence permits
- use arrays for dense states
- use top-down for sparse states
- use bottom-up for predictable dense states
BFS Performance
Useful improvements:
- mark visited when pushing
- encode bounded states as integers
- stop when target is popped
- use bidirectional BFS when neighbor generation is symmetric
- include all future-changing fields in visited
Compact key example:
state_id = ((mask * rows) + row) * cols + col
String State Performance
Useful improvements:
- memoize string indexes or
(i, j)pairs - precompute palindrome intervals if many checks are needed
- use trie prefixes to prune dictionary searches
- use border/failure links for repeated pattern matching
- use rolling hash carefully when many substring equality checks are needed
Divide/Recombine Performance
Useful improvements:
- return the exact summary parent needs
- avoid recomputing child summaries
- keep endpoint convention consistent
- do cross-boundary work while child summaries are ordered or indexed
- ensure parent returns the same summary type upward
Cheat Sheets
Universal Checklist
Goal:
What must be returned?
State/unit:
What does one call own?
Moves/splits:
What can happen next?
Stop/base:
When does the call finish directly?
Return:
What flows back or gets recorded?
Engine:
pure traversal, backtracking, DP, BFS, string structure, or recombine?
Pure Explorer Checklist
What marks a state as processed?
What neighbors are legal?
What stops movement?
Can each state be processed once?
Does the traversal need to return more than mark/count/boolean?
Choice Explorer Checklist
What path am I building?
What are legal choices?
When do I record?
What do I mutate?
What do I undo?
Constraint Explorer Checklist
What trackers make legality O(1)?
Do I check before mutating?
Do I update every tracker?
Do I undo every tracker?
Can I choose a more constrained variable first?
Bitmask Checklist
Can each item map to a stable bit?
What does bit i mean?
What is the all-done mask?
Does mask belong in memo or visited?
Is 2^n feasible?
DP Checklist
What is solve(state)?
What is the memo key?
What are base cases?
What are transitions?
What combines child answers?
Can memory be compressed?
BFS Checklist
Are moves equal cost?
What is the start state?
What is the target test?
What belongs in visited?
Do I mark when pushing?
Can I bound or encode states?
String State Checklist
Is state an index, pair, path, center, interval, trie node, automaton, or window?
What character operation moves it?
Does the state repeat?
Does it need undo?
Does reusable string memory avoid repeated comparisons?
Divide/Recombine Checklist
What unit does one call own?
What is the base case?
How does the unit split?
What does each child return?
Is there cross-boundary work?
How does the parent combine?
Does the parent return the same summary type?
One-Line Hooks
- Pure explorer: mark and move.
- Choice explorer: choose, recurse, undo.
- Constraint explorer: try only legal choices.
- Bitmask state: set becomes integer.
- DP explorer: repeated state gets cached.
- BFS explorer: shortest equal-cost path comes from layers.
- String state: index/pair/path/automaton moves through characters.
- Tree summary: child facts return through parent.
- Divide/recombine: split, solve children, combine summaries.
Final Debug Prompt
Before submitting, ask:
If I pause at this exact state or unit, do I know everything needed to solve the rest?
If no, add the missing state field or summary field.
Then ask:
Is my main work moving forward, caching repeated futures, or rebuilding upward?
The answer tells you the engine.