🌳 Pattern 06

Backtracking

Try every valid path — if it fails, undo and try the next one. Build answers piece by piece, prune bad branches early.

Core Idea: Choose → Explore → Unchoose
Problems: 15
Types: 5
Difficulty: Medium → Hard
🧠
Intuition — What Is Backtracking?
01
▾
💡 The Core Idea

You explore all possibilities by making a choice, going deeper, and undoing it when it leads nowhere — then trying the next option.

Real-world analogy: You're solving a Sudoku. You write a number in a cell, check if it violates any rule — if it does, you erase it and try the next digit. That erase step is backtracking.

Another analogy: GPS gives you a wrong turn. You don't restart from home — you go back to the last junction and take a different road.

❌ Without Backtracking

Generate ALL arrangements → filter valid ones → slow and wasteful

✅ With Backtracking

Prune a branch the moment it's invalid → explore only promising paths

🔑 The 3-Step Loop (runs at every node in the recursion tree)
STEP 1 — CHOOSE

Pick one option from available choices (a number, character, element, direction)

STEP 2 — EXPLORE

Recurse with that choice applied. Go deeper into the tree.

STEP 3 — UNCHOOSE

After recursion returns, undo the choice. Restore state for next iteration.

🔍
Identify the Type — Is It Subset, Permutation, or Something Else?
02
▾
🗺 Decision Flowchart — Read the Problem, Answer These 3 Questions
Does the problem ask you to find/generate all valid outputs?
NO → count/optimize only
❌ Not Backtracking
Use DP / Greedy
YES → enumerate all
Does it involve a 2D grid (word search, path)?
YES
🟦 GRID TYPE
visited[][] + 4 dirs
NO
Is it about splitting/partitioning a string?
YES
🟦 PARTITION TYPE
cut at every index
NO
Does order of elements matter in the output?
YES → [1,2] ≠ [2,1]
🟣 PERMUTATION TYPE
visited[] array
NO → [1,2] = [2,1]
Are there hard constraints per placement
(Sudoku, N-Queens)?
YES
🟠 CONSTRAINT TYPE
isValid() check
NO
🟢 SUBSET TYPE
start index (i+1)
TYPE 1
🟢 Subset / Combination
Order does NOT matter
[1,2] and [2,1] = same result
Keywords: all subsets, combinations, choose k from n
LC 78, 77, 39, 40, 90, 216
Code Identifier Use start index — loop from i = start, recurse with i+1 (or i for repetition)
TYPE 2
🟣 Permutation
Order DOES matter
[1,2] and [2,1] = different results
Keywords: all arrangements, permutations, orderings
LC 46, 47, 60, 943
Code Identifier Use boolean used[] — loop always from i = 0, skip used[i]
TYPE 3
🟠 Constraint Satisfaction
Each placement has hard rules
Must call isValid() before placing
Keywords: N-Queens, Sudoku, valid board
LC 51, 52, 37
Code Identifier if (!isValid()) continue inside loop — place, recurse row+1, unplace
TYPE 4
🟦 Grid / Path Search
2D matrix navigation
DFS in 4 directions
Keywords: word search, island, path exists
LC 79, 212, 489, 980
Code Identifier Mark cell grid[r][c]='#', explore 4 dirs, then restore original char
TYPE 5
🩵 String Partition
Cut a string at various positions
Validate each segment before adding
Keywords: palindrome partition, decode ways, IP addresses
LC 131, 93, 140
Code Identifier Loop end from start to n, check substring validity, recurse with end+1
⚡ Quick Comparison — The Most Confusing Part
Question to Ask Subset Type Permutation Type
Does [1,2] == [2,1] ?✅ Yes, same❌ No, different
Loop starts ati = start (forward only)i = 0 (always full scan)
State variableint startboolean[] used
Recurse withi + 1 (or i for reuse)same used[] passed down
Result added whenEvery node (subsets) / leaf (combos)Only at leaf (path.size == n)
Example problemLC 78 Subsets, LC 39 Comb SumLC 46 Permutations
📐
Universal Template — Memorize This One Structure
03
▾
📋 5-Part Structure — Every Backtracking Function Has These
1
Base Case

Goal reached? Save result and return. (path complete, sum == target, row == n)

2
Prune

Invalid state? Return immediately. (out of bounds, constraint violated, sum exceeded)

3
Loop Over Choices

For each available option at this level...

4
Choose + Explore

Apply the choice (add to path, mark used), then recurse.

5
Unchoose

After recursion returns, undo the choice. This is the backtrack step. Never skip it.

Java
Python
C++
Universal Template
// ── UNIVERSAL BACKTRACKING TEMPLATE ──────────────────────────
void backtrack(List<Integer> path, int start /* or other state */) {

    // ① BASE CASE ── goal reached?
    if (goalReached()) {
        result.add(new ArrayList<>(path));   // ← copy, not reference!
        return;
    }

    // ② PRUNE ── invalid state?
    if (isInvalid()) return;

    // ③ LOOP OVER CHOICES
    for (int i = start; i < choices.length; i++) {

        // ④ CHOOSE + EXPLORE
        path.add(choices[i]);             // make the move
        backtrack(path, i + 1);           // go deeper

        // ⑤ UNCHOOSE ← the backtrack step
        path.remove(path.size() - 1);    // undo the move
    }
}
# ── UNIVERSAL BACKTRACKING TEMPLATE ──────────────────────────
def backtrack(path, start):

    # ① BASE CASE
    if goal_reached():
        result.append(path[:])   # shallow copy
        return

    # ② PRUNE
    if is_invalid(): return

    # ③ LOOP
    for i in range(start, len(choices)):

        # ④ CHOOSE + EXPLORE
        path.append(choices[i])
        backtrack(path, i + 1)

        # ⑤ UNCHOOSE ← the backtrack step
        path.pop()
// ── UNIVERSAL BACKTRACKING TEMPLATE ──────────────────────────
void backtrack(vector<int>& path, int start) {

    // ① BASE CASE
    if (goalReached()) {
        result.push_back(path);
        return;
    }

    // ② PRUNE
    if (isInvalid()) return;

    // ③ LOOP
    for (int i = start; i < choices.size(); i++) {

        // ④ CHOOSE + EXPLORE
        path.push_back(choices[i]);
        backtrack(path, i + 1);

        // ⑤ UNCHOOSE
        path.pop_back();
    }
}
⚠️ #1 Beginner Mistake
  • Missing the unchoose step — the state gets corrupted. All subsequent branches will produce wrong answers.
  • Adding reference instead of copy — result.add(path) adds a reference. When path changes, the stored list changes too. Always use new ArrayList<>(path).
  • Not unmark-ing visited[] in permutation / grid problems.
🌳
Recursion Trees — See Exactly What Happens
04
▾
🟢 Subsets [1,2,3]
🟣 Permutations [1,2,3]
🟠 Combination Sum (target=7)
🟦 Word Search Grid
🟢 TYPE 1 — Subset Tree — Result added at EVERY node, not just leaves

Each node = a subset. At each level, you decide: include next element or skip to next. Start index moves forward so you never re-pick.

Input: [1, 2, 3] Each branch = "include this element, then recurse with start+1" ──────────────────────────────────────────────────────────────────────── backtrack(start=0, path=[]) add [] ✓ ┌───────────────┬───────────────┐ take 1 take 2 take 3 │ │ │ path=[1] path=[2] path=[3] add [1] ✓ add [2] ✓ add [3] ✓ ┌─────┬──┐ ┌─────┐ +2 +3 +3 │ │ │ [1,2] [1,3] [2,3] ✓ ✓ ✓ │ +3 │ [1,2,3] ✓ All 8 subsets: [], [1], [2], [3], [1,2], [1,3], [2,3], [1,2,3] → 2ⁿ = 2³ = 8 KEY: start index increments (i+1) so we never look back → no duplicates KEY: We add result at EVERY node (not just leaves) → that's what makes it "subsets"
🟣 TYPE 2 — Permutation Tree — Result added only at LEAVES, used[] tracks state

Every level = one position in the output. At each node, loop from 0 (not start), skip already-used elements via used[].

Input: [1, 2, 3] used[] starts as [F, F, F] Result added when path.size == 3 ──────────────────────────────────────────────────────────────────────── path=[], used=[F,F,F] ┌─────────────┬─────────────┐ pick 1 pick 2 pick 3 │ │ │ [1] used=[T,F,F] [2] used=[F,T,F] [3] used=[F,F,T] ┌────┐ ┌────┐ ┌────┐ p2 p3 p1 p3 p1 p2 │ │ │ │ │ │ [1,2][1,3] [2,1][2,3] [3,1][3,2] │ │ │ │ │ │ +3 +2 +3 +1 +2 +1 [1,2,3][1,3,2] [2,1,3][2,3,1] [3,1,2][3,2,1] ↑ unchoose: used[i]=false, path.remove() n! = 3! = 6 permutations Width at each level = (n - depth) remaining elements KEY: loop always starts at i=0, NOT at start → that's the permutation signal KEY: used[i]=true before recurse, used[i]=false after → classic backtrack
🟠 TYPE 1 (with pruning) — Combination Sum — Red nodes = PRUNED branches

Candidates=[2,3,6,7], target=7. Same element CAN be reused (recurse with same i, not i+1). Prune when sum exceeds target.

Candidates: [2,3,6,7] target=7 Sort first! Prune when sum > target ──────────────────────────────────────────────────────────────────────── sum=0, path=[] ┌──────────┬──────────┬──────────┐ +2 +3 +6 +7 │ │ │ │ sum=2 sum=3 sum=6 sum=7 → [7] ✓ ┌──┬──┬──┐ ┌──┬──┬──┐ ┌──┬────┐ +2 +3 +6 +7 +3 +6 +7 +6 +7→13❌ │ │ +6→8❌+7→9❌ 9❌10❌ 12❌ 4 5 ↑prune ↑prune ┌─┬─┐ ┌─┬─┐ +2+3 +2+3 │ │ │ +3→8❌ 6 7 7 │ │ └─→ [2,2,3] ✓ +3 [2,2,3]✓ [2,3,2]? ← No! We reuse same i (not i+1) but never go back → sorted order avoids dup ✅ Valid answers: [7], [2,2,3], [3,3+?→nope] Final: [[2,2,3], [7]] KEY PRUNE: if (sum + candidates[i] > target) break; ← works because array is sorted
🟦 TYPE 4 — Grid DFS Tree — Prune out-of-bounds + wrong char + already visited

Word="CAT". Starting at (0,0)='C'. Each node = one cell. 4 children = Up/Down/Left/Right. Mark '#' to avoid re-visiting same cell.

Grid: Word: "CAT" C A B Starting cell = (0,0) = 'C' X T E idx=0 → need 'C', idx=1 → need 'A', idx=2 → need 'T' D F G ──────────────────────────────────────────────────────────────────────── dfs(r=0,c=0,idx=0) grid[0][0]='C' ✓ → mark '#' ┌──────────┬──────────┬──────────┐ UP DOWN LEFT RIGHT │ │ │ │ r=-1 ❌ (1,0)='X'≠'A'❌ c=-1 ❌ (0,1)='A' ✓ → mark '#' outofbound char mismatch outofbound ┌────┬────┬────┐ UP DOWN LEFT RIGHT ❌ │ #❌ ❌ (already visited↑) (1,1)='T' ✓ → mark '#' │ idx=3 == word.length() → return TRUE ✓ ← After each return: restore grid[r][c] = original char (unchoose) KEY: grid[r][c]='#' to mark visited → serves as both "choose" and "visited check" KEY: grid[r][c]=tmp to restore → that IS the unchoose step PRUNE conditions: out of bounds, char != word[idx], already visited (#)
💻
Type Deep Dive — Full Code per Type
05
▾
🟢 TYPE 1 — Subset / Combination — LC 78 Subsets & LC 39 Combination Sum

Signal: "All subsets / combinations" — order doesn't matter — use start index.

Java — LC 78
Java — LC 39 (with reuse)
SUBSET TYPE
List<List<Integer>> result = new ArrayList<>();

public List<List<Integer>> subsets(int[] nums) {
    backtrack(nums, 0, new ArrayList<>());
    return result;
}

void backtrack(int[] nums, int start, List<Integer> path) {
    result.add(new ArrayList<>(path));  // ① add at EVERY node

    for (int i = start; i < nums.length; i++) {  // ③ start from 'start'
        path.add(nums[i]);                         // ④ choose
        backtrack(nums, i + 1, path);            // ④ explore (i+1 = no repeat)
        path.remove(path.size() - 1);            // ⑤ unchoose
    }
}
// Signal: "start" param + loop from start → SUBSET type
// LC 39 — Combination Sum (element CAN be reused)
void backtrack(int[] cands, int start, int remain, List<Integer> path) {
    if (remain == 0) {                 // ① base case: exact sum
        result.add(new ArrayList<>(path));
        return;
    }
    if (remain < 0) return;           // ② prune: exceeded target

    for (int i = start; i < cands.length; i++) {
        if (cands[i] > remain) break;  // sorted → no point continuing
        path.add(cands[i]);
        backtrack(cands, i, remain - cands[i], path);  // i not i+1 (reuse ok)
        path.remove(path.size() - 1);
    }
}
// Note: recurse with 'i' (not i+1) = same element can be reused
// Note: recurse with 'i+1' = each element used at most once (LC 40)
🟣 TYPE 2 — Permutation — LC 46 Permutations

Signal: "All arrangements / orderings" — order matters — use visited[] array, loop always from 0.

Java — LC 46
Java — LC 47 (with duplicates)
PERMUTATION TYPE
boolean[] used;

void backtrack(int[] nums, List<Integer> path) {
    if (path.size() == nums.length) {  // ① base: all elements placed
        result.add(new ArrayList<>(path));
        return;
    }
    for (int i = 0; i < nums.length; i++) {  // ③ always loop from 0!
        if (used[i]) continue;               // skip already in path
        used[i] = true;                       // ④ choose
        path.add(nums[i]);
        backtrack(nums, path);               // ④ explore
        used[i] = false;                      // ⑤ unchoose
        path.remove(path.size() - 1);
    }
}
// Signal: loop from 0 + used[] array → PERMUTATION type
// LC 47 — Permutations II (with duplicates)
// Extra: sort first + skip condition
Arrays.sort(nums);  // sort first!
boolean[] used = new boolean[nums.length];

void backtrack(int[] nums, List<Integer> path) {
    if (path.size() == nums.length) {
        result.add(new ArrayList<>(path));
        return;
    }
    for (int i = 0; i < nums.length; i++) {
        if (used[i]) continue;
        // Skip duplicate: same value, previous sibling already explored
        if (i > 0 && nums[i] == nums[i-1] && !used[i-1]) continue;
        used[i] = true;
        path.add(nums[i]);
        backtrack(nums, path);
        used[i] = false;
        path.remove(path.size() - 1);
    }
}
// !used[i-1] means: same value's "first" use hasn't finished yet → skip
🟠 TYPE 3 — Constraint Satisfaction — LC 51 N-Queens

Signal: Hard placement rules — must call isValid() before every placement. Place → recurse row+1 → unplace.

Java — LC 51 N-Queens
CONSTRAINT TYPE
void solve(char[][] board, int row) {
    if (row == board.length) {       // ① base: all rows filled
        result.add(build(board));
        return;
    }
    for (int col = 0; col < board.length; col++) {
        if (!isValid(board, row, col)) continue;  // ② prune invalid
        board[row][col] = 'Q';               // ④ choose: place queen
        solve(board, row + 1);               // ④ explore next row
        board[row][col] = '.';               // ⑤ unchoose: remove queen
    }
}

boolean isValid(char[][] board, int row, int col) {
    // Check column (no queen in same column above)
    for (int r = 0; r < row; r++)
        if (board[r][col] == 'Q') return false;
    // Check diagonals
    for (int r = row-1, c = col-1; r>=0&&c>=0; r--,c--)
        if (board[r][c] == 'Q') return false;
    for (int r = row-1, c = col+1; r>=0&&c<board.length; r--,c++)
        if (board[r][c] == 'Q') return false;
    return true;
}
// Signal: isValid() before placement + go row by row → CONSTRAINT type
🟦 TYPE 4 — Grid / Path — LC 79 Word Search

Signal: 2D grid, DFS in 4 directions, mark visited using '#' overwrite trick.

font-size:10px;color:var(--blue)">GRID TYPE
boolean exist(char[][] board, String word) {
    for (int r = 0; r < board.length; r++)
        for (int c = 0; c < board[0].length; c++)
            if (dfs(board, word, r, c, 0)) return true;
    return false;
}

boolean dfs(char[][] board, String word, int r, int c, int idx) {
    if (idx == word.length()) return true;  // base: full word matched
    if (r < 0 || r >= board.length || c < 0 || c >= board[0].length
        || board[r][c] != word.charAt(idx)) return false;  // prune

    char tmp = board[r][c];
    board[r][c] = '#';          // choose: mark visited in-place
    boolean found = dfs(board, word, r+1, c, idx+1)
                  || dfs(board, word, r-1, c, idx+1)
                  || dfs(board, word, r, c+1, idx+1)
                  || dfs(board, word, r, c-1, idx+1);
    board[r][c] = tmp;            // unchoose: restore cell
    return found;
}
// Signal: r/c params + 4 direction recursion + '#' overwrite → GRID type
🩵 TYPE 5 — String Partition — LC 131 Palindrome Partitioning

Signal: "Partition into valid segments" — loop end index, validate each substring, recurse from end+1.

Java — LC 131
PARTITION TYPE
void backtrack(String s, int start, List<String> path) {
    if (start == s.length()) {          // base: consumed whole string
        result.add(new ArrayList<>(path));
        return;
    }
    for (int end = start; end < s.length(); end++) {
        String sub = s.substring(start, end + 1);
        if (!isPalindrome(sub)) continue;  // prune: invalid segment
        path.add(sub);                        // choose
        backtrack(s, end + 1, path);        // explore from next char
        path.remove(path.size() - 1);       // unchoose
    }
}
// Signal: loop 'end' from start, validate substring → PARTITION type
// Same pattern for LC 93 (valid IP) — just validate IP segment instead
🎯
Practice Problems — Filtered by Type
06
▾
Progress: 0 / 58 solved
📺 Pepcoding Level 1 — Recursion Basics
EasyPrint 1 to N or N to 1 using Recursion GFG↗BASICS
EasyCalculate Height of Binary Tree GFG↗BASICS
EasySort an Array using Recursion GFG↗BASICS
EasySort a Stack using Recursion GFG↗BASICS
EasyDelete Middle Element from Stack GFG↗BASICS
EasyReverse a Stack using Recursion GFG↗BASICS
MedKth Symbol in Grammar LC 779↗BASICS
MedTower of Hanoi GFG↗BASICS
📺 Pepcoding — Subsets & Permutations
EasyPrint Subsets / Subsequences / Power Set of String LC 78↗SUBSET
EasyPrint Unique Subsets / Unique Subsequences LC 90↗SUBSET
EasyPermutations with Spaces GFG↗PERMUTATION
EasyPermutation with Case Change GFG↗PERMUTATION
MedLetter Case Permutation (digits allowed) LC 784↗PERMUTATION
MedGenerate All Balanced Parentheses LC 22↗SUBSET
MedPrint N-Bit Binary Numbers having #1s ≥ #0s GFG↗SUBSET
MedJosephus Problem LC 1823↗BASICS
📺 Pepcoding — Array Index & Get Methods
EasyFirst Index of Occurrence in Array GFG↗BASICS
EasyLast Index of Occurrence in Array GFG↗BASICS
EasyAll Indices of Occurrence in Array GFG↗BASICS
EasyGet Subsequences (return array) LC 78↗SUBSET
MedGet Keypad Combinations (return array) LC 17↗PERMUTATION
MedGet Stair Paths (1,2,3 steps) GFG↗GRID/PATH
MedGet Maze Paths (h/v moves only) GFG↗GRID/PATH
MedGet Maze Paths with Jumps (h,v,diagonal) GFG↗GRID/PATH
MedPrint Keypad Combinations LC 17↗PERMUTATION
EasyPrint Stair Paths GFG↗GRID/PATH
EasyPrint Maze Paths GFG↗GRID/PATH
MedPrint Maze Paths with Jumps GFG↗GRID/PATH
MedPrint Permutations of String LC 46↗PERMUTATION
MedPrint Encodings (decode ways) LC 91↗PARTITION
📺 Pepcoding — Backtracking (Grid + Constraint)
MedFlood Fill LC 733↗GRID
MedTarget Sum Subsets GFG↗SUBSET
HardN Queens LC 51↗CONSTRAINT
HardKnight's Tour Problem GFG↗CONSTRAINT
📺 Pepcoding Level 2 — Advanced Backtracking
MedPrint Abbreviations GFG↗PARTITION
HardN Queens using Branch and Bound LC 51↗CONSTRAINT
HardMax Score of Words LC 1255↗SUBSET
MedPrint Numbers in Lexicographical Order LC 386↗BASICS
MedGold Mine (Max connected gold) GFG↗GRID
HardSudoku Solver LC 37↗CONSTRAINT
HardCrossword Puzzle GFG↗CONSTRAINT
HardCryptarithmetic Puzzle GFG↗CONSTRAINT
MedFriends Pairing Problem GFG↗PERMUTATION
🎯 Classic LeetCode Problems
EasyLC 78 — SubsetsSUBSET
EasyLC 77 — CombinationsSUBSET
MedLC 39 — Combination SumSUBSET
MedLC 40 — Combination Sum II (duplicates)SUBSET
MedLC 90 — Subsets II (duplicates)SUBSET
MedLC 22 — Generate ParenthesesSUBSET
MedLC 46 — PermutationsPERMUTATION
MedLC 47 — Permutations II (duplicates)PERMUTATION
MedLC 17 — Letter Combinations of a Phone NumberPERMUTATION
HardLC 51 — N-QueensCONSTRAINT
HardLC 52 — N-Queens IICONSTRAINT
HardLC 37 — Sudoku SolverCONSTRAINT
MedLC 79 — Word SearchGRID
HardLC 212 — Word Search IIGRID
MedLC 131 — Palindrome PartitioningPARTITION
⚡
Cheatsheet — Patterns, Tricks & Complexity
07
▾
🔑 3 Questions to Identify Any Backtracking Type
Q1

Does order matter?

YES → Permutation (used[])
NO → Subset (start index)

Q2

Is it a 2D grid?

YES → Grid (r,c + 4 dirs)
NO → Not grid

Q3

Hard placement rules?

YES → Constraint (isValid())
String splits? → Partition

🔁 Duplicates Handling — Sort + Skip Pattern
// Subset with duplicates (LC 40, LC 90)
Arrays.sort(nums);
for (int i = start; i < nums.length; i++) {
    if (i > start && nums[i] == nums[i-1]) continue;  // skip same-level dup
    // ... backtrack body
}
// i > start = same value already tried at this level → skip

// Permutation with duplicates (LC 47)
if (i > 0 && nums[i] == nums[i-1] && !used[i-1]) continue;
// !used[i-1] = previous same-value already explored and backtracked → skip
📊 Time Complexity Reference
TypeTimeSpaceWhy
🟢 SubsetsO(2ⁿ × n)O(n)2 choices per element, n to copy
🟣 PermutationsO(n! × n)O(n)n! leaves, copy each takes O(n)
🟠 Combination SumO(2^t)O(t)t = target value
🟠 N-QueensO(n!)O(n²)Board storage per state
🟦 Word SearchO(m×n×4^L)O(L)4 dirs from every cell, L=word len
🩵 Palindrome Part.O(n × 2ⁿ)O(n)2ⁿ⁻¹ ways to partition
💬 5 Sentences to Say in Every Interview
  1. "I recognize this as backtracking — we need all valid [subsets / arrangements / paths]."
  2. "My state at each node is [current path + start index / used[] array]."
  3. "Base case is [path.size == n / remain == 0 / start == s.length()]."
  4. "I'll prune when [sum exceeds target / placement is invalid / out of bounds]."
  5. "After each recursive call, I undo the change to restore state for the next branch."
🧪
Quiz — Can You Identify the Type?
08
▾
Q1 / 5 — TYPE IDENTIFICATION
"Find all unique combinations of numbers that sum to a target. Each number may be used multiple times." — What backtracking type is this?
✅ "Combinations" + order doesn't matter ([2,3] = [3,2]) = Subset type. Use start index. Since reuse is allowed, recurse with same i (not i+1). Base case: remain == 0.
Q2 / 5 — CODE SIGNAL
You see this in a backtracking function: if (used[i]) continue; — What type is this?
✅ used[i] + loop always from i=0 = Permutation type. This is the single clearest code signal. Subset type uses an int start parameter and loops from start, never from 0.
Q3 / 5 — MISTAKE DETECTION
A student writes: result.add(path); inside their backtrack function. What is wrong?
✅ Classic bug. path is an object reference. After unchoose modifies it, the "saved" result also changes — they're the same object. Fix: result.add(new ArrayList<>(path)) to create an independent copy.
Q4 / 5 — PRUNING
In Combination Sum with sorted candidates, why use break instead of continue when candidates[i] > remain?
✅ Sorted array means candidates are monotonically increasing. If candidates[i] > remain, then candidates[i+1] and beyond are also too large. break exits the loop entirely (better pruning). continue would wastefully check the next element which is also invalid.
Q5 / 5 — UNCHOOSE IN GRID
In Word Search, after marking board[r][c] = '#' and the DFS returns, you MUST restore the cell. Why?
✅ The '#' prevents cycles only within the CURRENT path. Once that path is done (DFS returned), the cell must be freed for other paths to use. This is exactly the unchoose step — board[r][c] = tmp restores the cell for all other branches.