Bird
Raised Fist0
DSA C++programming

Why Greedy Works and When It Fails in DSA C++ - Why This Pattern

Choose your learning style10 modes available
Mental Model
Greedy picks the best choice at each step hoping it leads to the best overall result. Sometimes this works perfectly, but sometimes it misses better solutions that need planning ahead.
Analogy: Imagine choosing snacks from a buffet by always picking the tastiest-looking item first. Sometimes you get a great meal quickly, but other times you miss a better combination if you planned your picks differently.
Choices: [Step1] -> [Step2] -> [Step3] -> ... -> [Final]
Greedy: picks best at each step -> hopes final is best
Plan: looks ahead before picking -> finds best final
Dry Run Walkthrough
Input: Coins: [1, 3, 4], Amount: 6, Goal: Minimize coins to make 6
Goal: Show greedy picking largest coin first can fail to find minimum coins
Step 1: Pick largest coin ≤ 6: 4
Picked: 4 -> Remaining amount: 2
Why: Greedy picks biggest coin to reduce amount quickly
Step 2: Pick largest coin ≤ 2: 1
Picked: 4 -> 1 -> Remaining amount: 1
Why: Greedy again picks biggest coin possible
Step 3: Pick largest coin ≤ 1: 1
Picked: 4 -> 1 -> 1 -> Remaining amount: 0
Why: Greedy finishes by picking smallest coin
Step 4: Calculate total coins used
Coins used: 3 (4,1,1)
Why: Greedy solution uses 3 coins
Step 5: Check optimal solution by planning
Optimal coins: 2 (3,3)
Why: Better solution exists by picking two 3 coins
Result:
Picked coins: 4 -> 1 -> 1 -> null (3 coins)
Optimal coins: 3 -> 3 -> null (2 coins)
Annotated Code
DSA C++
#include <iostream>
#include <vector>
using namespace std;

// Greedy coin change: picks largest coin each time
int greedyCoinChange(const vector<int>& coins, int amount) {
    int count = 0;
    int remaining = amount;
    int i = coins.size() - 1; // start from largest coin
    while (remaining > 0 && i >= 0) {
        if (coins[i] <= remaining) {
            remaining -= coins[i]; // reduce amount by coin value
            count++;
        } else {
            i--; // try smaller coin
        }
    }
    if (remaining != 0) return -1; // no solution
    return count;
}

int main() {
    vector<int> coins = {1, 3, 4};
    int amount = 6;
    int result = greedyCoinChange(coins, amount);
    cout << "Greedy coins used: " << result << "\n";
    cout << "Optimal coins used: 2 (3 + 3)\n";
    return 0;
}
while (remaining > 0 && i >= 0) {
loop until amount is zero or no coins left
if (coins[i] <= remaining) {
check if current coin fits in remaining amount
remaining -= coins[i];
reduce remaining amount by chosen coin
count++;
increment count of coins used
else { i--; }
try next smaller coin if current coin too big
OutputSuccess
Greedy coins used: 3 Optimal coins used: 2 (3 + 3)
Complexity Analysis
Time: O(n) because we try each coin at most once while reducing amount
Space: O(1) since only counters and indexes are used
vs Alternative: Dynamic programming finds optimal solution in O(n*amount) time but uses more space and is slower
Edge Cases
Amount zero
Returns zero coins needed immediately
DSA C++
while (remaining > 0 && i >= 0) {
No coin fits amount
Returns -1 indicating no solution
DSA C++
if (remaining != 0) return -1;
Single coin equals amount
Returns 1 coin used
DSA C++
if (coins[i] <= remaining) {
When to Use This Pattern
When a problem asks for an optimal choice step-by-step and the choices are independent, try greedy; but if choices affect future options, greedy may fail.
Common Mistakes
Mistake: Assuming greedy always gives optimal solution without checking
Fix: Test greedy on small examples and compare with planning or dynamic programming
Summary
Greedy picks the best immediate choice hoping for the best overall result.
Use greedy when local best choices lead to global best solution.
The key insight is greedy works only if future choices are not hurt by current ones.

Practice

(1/5)
1. What is the main reason a greedy algorithm works correctly for some problems?
easy
A. Because it makes the best choice at each step hoping for a global optimum
B. Because it tries all possible solutions and picks the best one
C. Because it uses recursion to explore all paths
D. Because it sorts the input data before processing

Solution

  1. Step 1: Understand greedy choice property

    A greedy algorithm picks the best option available at each step without reconsidering previous choices.
  2. Step 2: Connect greedy choice to global optimum

    This local best choice leads to a global optimum only if the problem has the greedy choice property and optimal substructure.
  3. Final Answer:

    Because it makes the best choice at each step hoping for a global optimum -> Option A
  4. Quick Check:

    Greedy = local best choice [OK]
Hint: Greedy picks best now, not all possibilities [OK]
Common Mistakes:
  • Thinking greedy tries all solutions
  • Confusing greedy with backtracking
  • Assuming sorting alone makes greedy work
2. Which of the following is the correct syntax to select the next item in a greedy algorithm loop in C++?
easy
A. for (auto item : items) { choose item; }
B. for (int i = 0 i < n; i++) { choose item[i]; }
C. while (i <= n) { choose item[i]; i++; }
D. do { choose item[i]; i--; } while (i > 0);

Solution

  1. Step 1: Identify correct C++ loop syntax for iteration

    The range-based for loop for (auto item : items) is modern and correct for iterating over a container.
  2. Step 2: Check other options for correctness

    for (int i = 0 i < n; i++) { choose item[i]; } is missing semicolons and proper syntax. while (i <= n) { choose item[i]; i++; } uses while but lacks initialization shown. do { choose item[i]; i--; } while (i > 0); decrements i incorrectly.
  3. Final Answer:

    for (auto item : items) { choose item; } -> Option A
  4. Quick Check:

    Range-based for loop is correct syntax [OK]
Hint: Use range-based for loops for clean iteration [OK]
Common Mistakes:
  • Missing semicolons in for loop
  • Using wrong loop conditions
  • Decrementing index when should increment
3. Consider the following C++ code snippet for selecting intervals greedily by earliest finish time:
struct Interval {
  int start, end;
};

bool compare(Interval a, Interval b) {
  return a.end < b.end;
}

int main() {
  std::vector<Interval> intervals = {{1,4}, {3,5}, {0,6}, {5,7}, {8,9}};
  std::sort(intervals.begin(), intervals.end(), compare);
  int count = 0, last_end = -1;
  for (auto interval : intervals) {
    if (interval.start >= last_end) {
      count++;
      last_end = interval.end;
    }
  }
  std::cout << count << std::endl;
  return 0;
}
What is the output of this program?
medium
A. 5
B. 4
C. 3
D. 2

Solution

  1. Step 1: Sort intervals by end time

    Sorted intervals by end: {1,4}, {3,5}, {0,6}, {5,7}, {8,9}
  2. Step 2: Select intervals greedily

    Select {1,4} (count=1, last_end=4), skip {3,5} (start 3 < 4), skip {0,6} (start 0 < 4), select {5,7} (start 5 >= 4, count=2, last_end=7), select {8,9} (start 8 >= 7, count=3, last_end=9)
  3. Step 3: Count total selected intervals

    Total selected intervals = 3
  4. Final Answer:

    3 -> Option C
  5. Quick Check:

    Greedy interval selection count = 3 [OK]
Hint: Sort by finish time, pick non-overlapping intervals [OK]
Common Mistakes:
  • Counting overlapping intervals
  • Not sorting intervals correctly
  • Updating last_end incorrectly
4. The following code attempts to solve the coin change problem using a greedy approach:
int coins[] = {25, 10, 5, 1};
int amount = 30;
int count = 0;
for (int i = 0; i < 4; i++) {
  while (amount >= coins[i]) {
    amount -= coins[i];
    count++;
  }
}
std::cout << count << std::endl;
What is the main issue with this greedy approach?
medium
A. It always gives the minimum number of coins
B. It may fail for some coin sets where greedy is not optimal
C. It causes a syntax error due to missing semicolons
D. It runs infinitely because amount never decreases

Solution

  1. Step 1: Understand greedy coin change approach

    The code picks largest coin repeatedly until amount is reduced to zero.
  2. Step 2: Identify greedy failure cases

    Greedy works for US coins but fails for some coin sets where smaller coins combined give fewer coins than greedy picks.
  3. Final Answer:

    It may fail for some coin sets where greedy is not optimal -> Option B
  4. Quick Check:

    Greedy coin change can fail [OK]
Hint: Greedy coin change fails on non-canonical coin sets [OK]
Common Mistakes:
  • Assuming greedy always gives minimum coins
  • Confusing syntax errors with logic errors
  • Ignoring infinite loop possibility
5. You want to select activities to attend from a list with start and end times. The greedy algorithm picks the earliest finishing activity first. However, if activities have the same end time, it picks the one with the earliest start time. Why might this tie-break rule cause the greedy algorithm to fail in some cases?
hard
A. Because tie-break rules do not affect greedy correctness
B. Because earliest start time always leads to the best solution
C. Because sorting by end time is not needed in greedy algorithms
D. Because picking earliest start time among ties may block more future activities

Solution

  1. Step 1: Understand tie-breaking in activity selection

    Greedy sorts by earliest finish time. Ties in end time use earliest start as tie-breaker.
  2. Step 2: Analyze effect on greedy selection

    Picking the earliest start time among tied end times may block more future activities, reducing the total number of activities selected.
  3. Step 3: Confirm impact on optimality

    This tie-break rule can cause the greedy algorithm to fail to find the maximum set of non-overlapping activities.
  4. Final Answer:

    Because picking earliest start time among ties may block more future activities -> Option D
  5. Quick Check:

    Tie-break can affect future selections [OK]
Hint: Tie-breaks can affect greedy correctness when ends tie [OK]
Common Mistakes:
  • Thinking tie-breaks do not affect optimality
  • Assuming all tie-breaks are harmless
  • Ignoring impact of start times on future choices
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