Bird
Raised Fist0
DSA Cprogramming

Why Backtracking and What Greedy Cannot Solve in DSA C - Why This Pattern

Choose your learning style10 modes available
Mental Model
Backtracking tries all possible choices step-by-step to find the best solution, while greedy picks the best choice at each step without looking ahead.
Analogy: Imagine choosing dishes at a buffet: greedy picks the tastiest dish first without thinking about the whole meal, but backtracking tries different combinations to make the best full meal.
Start:
Choices: [A, B, C]
Greedy picks -> A
Backtracking tries -> A -> B -> C
                      ↓    ↓    ↓
                    explore all combos
Dry Run Walkthrough
Input: Set of numbers: [3, 4, 5, 8], target sum: 7
Goal: Find if any combination of numbers sums exactly to 7
Step 1: Greedy checks nums[3]=8 > 7, skips
Sum: 0
Why: Too big for target
Step 2: Greedy picks nums[2]=5 ≤ 7
Chosen: [5]
Sum: 5
Why: Greedy picks next largest fitting
Step 3: Greedy checks nums[1]=4 > 7-5=2 skips; nums[0]=3 > 2 skips
Chosen: [5]
Sum: 5
Why: Greedy cannot add more, sum != target, fails
Step 4: Backtracking tries 3 first, sum=3 < 7, continue
Chosen: [3]
Sum: 3
Why: Backtracking explores all options
Step 5: Backtracking adds 4, sum=7 == 7, found!
Chosen: [3, 4]
Sum: 7
Why: Valid combination without the larger numbers
Result:
Greedy: No combination found
Backtracking: Found [3, 4] Sum: 7
Annotated Code
DSA C
#include <stdio.h>
#include <stdbool.h>

bool backtrack(int nums[], int n, int target, int index, int current_sum) {
    if (current_sum == target) return true; // found exact sum
    if (current_sum > target || index == n) return false; // overshoot or no more numbers

    // choose current number
    if (backtrack(nums, n, target, index + 1, current_sum + nums[index]))
        return true;

    // skip current number
    if (backtrack(nums, n, target, index + 1, current_sum))
        return true;

    return false; // no solution found
}

bool greedy(int nums[], int n, int target) {
    int sum = 0;
    for (int i = n - 1; i >= 0; i--) {
        if (nums[i] <= target - sum) {
            sum += nums[i];
            if (sum == target) return true;
        }
    }
    return false;
}

int main() {
    int nums[] = {3, 4, 5, 8};
    int n = 4;
    int target = 7;

    if (greedy(nums, n, target))
        printf("Greedy: Found a combination summing to %d\n", target);
    else
        printf("Greedy: No combination found for %d\n", target);

    if (backtrack(nums, n, target, 0, 0))
        printf("Backtracking: Found a combination summing to %d\n", target);
    else
        printf("Backtracking: No combination found for %d\n", target);

    return 0;
}
if (current_sum == target) return true; // found exact sum
stop when exact sum is found
if (current_sum > target || index == n) return false; // overshoot or no more numbers
stop if sum too big or no more numbers
if (backtrack(nums, n, target, index + 1, current_sum + nums[index])) return true;
try including current number
if (backtrack(nums, n, target, index + 1, current_sum)) return true;
try excluding current number
for (int i = n - 1; i >= 0; i--) { if (nums[i] <= target - sum) { sum += nums[i]; if (sum == target) return true; } }
greedy picks largest numbers fitting in remaining sum
OutputSuccess
Greedy: No combination found for 7 Backtracking: Found a combination summing to 7
Complexity Analysis
Time: O(2^n) because backtracking tries all subsets, greedy is O(n) because it scans once
Space: O(n) for backtracking recursion stack, O(1) for greedy
vs Alternative: Backtracking is slower but finds all solutions; greedy is fast but can miss valid combinations
Edge Cases
Empty input array
Backtracking returns false immediately; greedy returns false
DSA C
if (current_sum > target || index == n) return false;
Target sum zero
Backtracking returns true immediately; greedy returns false as no numbers needed
DSA C
if (current_sum == target) return true;
No combination sums to target
Backtracking explores all and returns false; greedy may return false early
DSA C
return false; // no solution found
When to Use This Pattern
When a problem requires exploring all possible combinations or subsets to find a valid solution, and greedy choices fail, use backtracking to try all options systematically.
Common Mistakes
Mistake: Assuming greedy always finds a solution if one exists
Fix: Use backtracking to explore all combinations when greedy fails
Mistake: Not backtracking after overshooting target sum
Fix: Add condition to stop and backtrack when sum exceeds target
Summary
Backtracking tries all possible choices to find a valid solution, while greedy picks the best immediate choice.
Use backtracking when greedy fails to find a solution because the problem requires exploring many combinations.
The key insight is that greedy can miss solutions because it never revisits earlier choices, but backtracking explores all possibilities.

Practice

(1/5)
1. Why is backtracking preferred over greedy algorithms in problems like the N-Queens puzzle?
easy
A. Because backtracking explores all possible solutions and can backtrack on wrong choices
B. Because greedy algorithms always find the optimal solution quickly
C. Because backtracking uses less memory than greedy algorithms
D. Because greedy algorithms do not use recursion

Solution

  1. Step 1: Understand problem requirements

    The N-Queens puzzle requires placing queens so none attack each other, needing exploration of many possibilities.
  2. Step 2: Compare algorithm approaches

    Backtracking tries all options and undoes wrong choices, while greedy picks locally best choices that may fail globally.
  3. Final Answer:

    Because backtracking explores all possible solutions and can backtrack on wrong choices -> Option A
  4. Quick Check:

    Backtracking explores all options = A [OK]
Hint: Backtracking tries all paths; greedy picks local best only [OK]
Common Mistakes:
  • Thinking greedy always finds the best solution
  • Confusing memory use between backtracking and greedy
  • Assuming backtracking is always slower without context
2. Which of the following is the correct syntax to start a backtracking function in C for solving a problem recursively?
easy
A. int backtrack[] = {0};
B. void backtrack(int step) { /* code */ }
C. backtrack() -> void { /* code */ }
D. function backtrack(int step) { /* code */ }

Solution

  1. Step 1: Identify valid C function syntax

    In C, functions are declared with return type, name, and parameters inside parentheses.
  2. Step 2: Check each option

    A matches C syntax; B is an array declaration; C and D use non-C syntax.
  3. Final Answer:

    void backtrack(int step) { /* code */ } -> Option B
  4. Quick Check:

    C function syntax = A [OK]
Hint: C functions start with return type and parentheses [OK]
Common Mistakes:
  • Using JavaScript or other language syntax in C
  • Confusing arrays with functions
  • Omitting return type in function declaration
3. Consider the following C code snippet for a backtracking approach to find subsets of {1, 2}:
void backtrack(int start, int n) {
    if (start == n) {
        printf("Reached end\n");
        return;
    }
    backtrack(start + 1, n);
    backtrack(start + 1, n);
}
int main() {
    backtrack(0, 2);
    return 0;
}
What will be the output when this code runs?
medium
A. Reached end\n
B. Reached end\nReached end\n
C. Reached end\nReached end\nReached end\nReached end\n
D. No output

Solution

  1. Step 1: Trace recursive calls

    backtrack(0,2) calls backtrack(1,2) twice; each backtrack(1,2) calls backtrack(2,2) twice.
  2. Step 2: Count base case hits

    backtrack(2,2) prints "Reached end"; it is called 4 times total (2 calls from each of 2 calls at start=1).
  3. Final Answer:

    Reached end\nReached end\nReached end\nReached end\n -> Option C
  4. Quick Check:

    4 base calls print output = A [OK]
Hint: Count recursive calls reaching base case carefully [OK]
Common Mistakes:
  • Counting only one base case print
  • Confusing number of recursive calls
  • Ignoring duplicate calls in recursion
4. The following C code attempts to solve the subset sum problem using backtracking but has a bug:
void backtrack(int index, int sum, int target, int arr[], int n) {
    if (sum == target) {
        printf("Found subset\n");
        return;
    }
    if (index == n || sum > target) {
        return;
    }
    backtrack(index + 1, sum + arr[index], target, arr, n);
    backtrack(index + 1, sum, target, arr, n);
}
int main() {
    int arr[] = {2, 4, 6};
    backtrack(0, 0, 6, arr, 3);
    return 0;
}
What is the bug in this code?
medium
A. It does not print all subsets that sum to target
B. It does not check if sum exceeds target before recursion
C. It does not handle negative numbers in array
D. It does not stop recursion after finding one subset

Solution

  1. Step 1: Analyze base case for sum == target

    When sum equals target, it prints but continues recursion because no stop condition after printing.
  2. Step 2: Identify missing stop after success

    Function returns only from current call, but parent calls continue exploring other subsets.
  3. Final Answer:

    It does not stop recursion after finding one subset -> Option D
  4. Quick Check:

    Missing stop after success = B [OK]
Hint: Stop recursion immediately after finding a valid subset [OK]
Common Mistakes:
  • Assuming printing once stops all recursion
  • Ignoring need to return from all recursive calls
  • Confusing sum checks with recursion control
5. You want to solve the problem of finding all combinations of coins that sum to a target amount. Why can't a greedy algorithm always solve this correctly, and how does backtracking help? Choose the best explanation.
hard
A. Greedy picks largest coins first which may miss combinations; backtracking tries all coin choices systematically
B. Greedy uses more memory; backtracking uses less memory
C. Greedy is slower than backtracking for coin problems
D. Backtracking only tries one coin at a time, greedy tries all

Solution

  1. Step 1: Understand greedy approach limitation

    Greedy picks largest coin repeatedly, which can miss valid combinations with smaller coins.
  2. Step 2: Understand backtracking advantage

    Backtracking tries all coin combinations by exploring all choices and backtracking on failures.
  3. Final Answer:

    Greedy picks largest coins first which may miss combinations; backtracking tries all coin choices systematically -> Option A
  4. Quick Check:

    Greedy misses combos; backtracking explores all = A [OK]
Hint: Greedy misses combos; backtracking explores all systematically [OK]
Common Mistakes:
  • Assuming greedy always finds all solutions
  • Confusing memory use with correctness
  • Thinking backtracking is always slower without context
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard