Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/PROBLEMS.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ Complete list of all solved problems, organized by difficulty and topic.
- [0072 - Edit Distance](../leetcode/medium/0072-edit-distance) ![Medium](https://img.shields.io/badge/Medium-orange)
- [0139 - Word Break](../leetcode/medium/0139-word-break) ![Medium](https://img.shields.io/badge/Medium-orange)
- [0198 - House Robber](../leetcode/medium/0198-house-robber) ![Medium](https://img.shields.io/badge/Medium-orange)
- [0322 - Coin Change](../leetcode/medium/0322-coin-change) ![Medium](https://img.shields.io/badge/Medium-orange)
- [0413 - Arithmetic Slices](../leetcode/medium/0413-arithmetic-slices) ![Medium](https://img.shields.io/badge/Medium-orange)
- [0718 - Maximum Length of Repeated Subarray](../leetcode/medium/0718-maximum-length-of-repeated-subarray) ![Medium](https://img.shields.io/badge/Medium-orange)
- [1250 - Longest Common Subsequence](../leetcode/medium/1250-longest-common-subsequence) ![Medium](https://img.shields.io/badge/Medium-orange)
Expand Down Expand Up @@ -294,6 +295,7 @@ Complete list of all solved problems, organized by difficulty and topic.
- [0072 - Edit Distance](../leetcode/medium/0072-edit-distance) - Medium
- [0139 - Word Break](../leetcode/medium/0139-word-break) - Medium
- [0198 - House Robber](../leetcode/medium/0198-house-robber) - Medium
- [0322 - Coin Change](../leetcode/medium/0322-coin-change) - Medium

### Graphs (BFS/DFS)

Expand Down
195 changes: 195 additions & 0 deletions leetcode/medium/0322-coin-change/POST_MORTEM.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
# Interview Debrief — Coin Change

**Date:** 2026-02-13
**Problem:** [322. Coin Change](https://leetcode.com/problems/coin-change/) — Medium
**Duration:** ~75 minutes (estimated based on 4 cycles)
**Mode:** Guided TDD (Coach Mode)

**Duration Estimation:**

- Cycle 1: ~10 minutes (base case)
- Cycle 2: ~35 minutes (full DP implementation + debugging initialization bug)
- Cycle 3: ~10 minutes (verification test)
- Cycle 4: ~10 minutes (learner-authored test)
- Discussion/pattern checkpoints: ~10 minutes

---

## Session Overview

The candidate demonstrated strong problem-solving ability and successfully implemented a classic unbounded knapsack DP solution. They correctly identified the Dynamic Programming pattern early, articulated the state representation and recurrence relation, and worked through a significant debugging challenge independently. Communication was clear and thoughtful, though complexity analysis needed refinement. Overall, this was a solid medium-problem performance with good debugging resilience.

---

## Problem Solving

### Score: 4/5

**Strengths:**

- Correctly identified Dynamic Programming as the appropriate pattern in cycle 1
- Understood the subproblem structure: `dp[i]` = minimum coins for amount `i`
- Correctly derived array size as `amount + 1`
- Grasped the recurrence relation `dp[i] = min(dp[i], dp[i - coin] + 1)` after guided questions
- Asked clarifying questions about constraints before proposing tests (showed good problem-solving discipline)

**Areas for Improvement:**

- Initially struggled to articulate the recurrence relation clearly (needed follow-up questions on what to add and how to choose minimum)
- Took 2-3 iterations to fully clarify what `dp[i]` stores and how to compute it

**Help Needed:** Minimal — Level 1 guiding questions during pattern checkpoint in cycle 2. Once the recurrence relation was clear, implementation was independent.

---

## Coding

### Score: 3.5/5

**Strengths:**

- Clean, readable code with proper TypeScript syntax
- Correctly implemented nested loops with proper bounds checking (`i - coin >= 0`)
- Used `Math.min()` appropriately for the DP recurrence
- Successfully wrote a learner-authored test in cycle 4 with clear naming

**Areas for Improvement:**

- Made a critical initialization bug in cycle 2: used `Number.MIN_SAFE_INTEGER` instead of `MAX_SAFE_INTEGER`, breaking the `Math.min()` logic
- Then attempted to fix with `-1` initialization, which also broke the logic for valid cases
- These mistakes suggest incomplete mental simulation of how `Math.min()` behaves with initial sentinel values

**Debugging Process:**

- After I pointed out the issue with `MIN_SAFE_INTEGER`, the candidate needed a concrete example (`coins = [2], amount = 2`) to see why it failed
- Attempted an alternative approach (`-1` initialization) that still had the same underlying issue
- Successfully corrected to `MAX_SAFE_INTEGER` after understanding that the sentinel must be larger than any possible answer
- Debugging was methodical but required guidance to see the root cause

---

## Verification

### Score: 4/5

**Strengths:**

- Proactively asked about constraints (empty arrays, negative amounts) before proposing tests — excellent practice
- Chose strategic test cases: base case (amount = 0), impossible case (even coins, odd amount), optimal solution with multiple coins
- Test progression was logical and incremental
- Wrote a clear, descriptive learner-authored test in cycle 4

**Areas for Improvement:**

- Did not catch the initialization bug through mental testing before running the code
- Could have traced through a simple example (e.g., `amount = 2`) manually to verify the logic

---

## Communication

### Score: 4.5/5

**Strengths:**

- Asked thoughtful clarifying questions about constraints upfront
- Clearly articulated pattern understanding: "Dynamic programming... overlapping subproblems... minimum between current and previous"
- Responded well to follow-up questions, refining answers iteratively
- Asked excellent meta-question: "Should it be O(n²) if both loops iterate over the same value?" — shows active learning

**Areas for Improvement:**

- Initial explanations were sometimes vague (e.g., "store the current amount based on the coin") and needed refinement through Q&A

---

## Complexity Analysis

### Score: 3/5

**Strengths:**

- Correctly identified space complexity as O(n) for the dp array
- Understood that nested loops contribute to time complexity
- After correction, grasped the distinction between O(n²) and O(n × m) and asked a great follow-up question to solidify understanding

**Areas for Improvement:**

- Initially stated time complexity as O(n²), missing that the inner loop iterates over `coins.length`, not `amount`
- Needed correction to understand that different iteration variables yield O(n × m), not O(n²)
- This is a common mistake but important to catch in interviews, especially for multi-variable DP problems

---

## Pattern Recognition

- **Pattern Used:** Dynamic Programming (Unbounded Knapsack variant)
- **Key Insight:** Build up solutions for amounts 0 to target by trying each coin and taking the minimum across all options. The recurrence `dp[i] = min(dp[i], dp[i - coin] + 1)` captures this optimally.
- **Pattern Checkpoint Results:** 2/2 cycles with pattern checkpoints (cycle 1: understood state structure; cycle 2: derived recurrence relation after guided questions)
- **Related Problems to Practice:**
- [518. Coin Change II](https://leetcode.com/problems/coin-change-ii/) — Count number of ways (not minimum) to make change
- [377. Combination Sum IV](https://leetcode.com/problems/combination-sum-iv/) — Order matters (permutations)
- [279. Perfect Squares](https://leetcode.com/problems/perfect-squares/) — Same pattern with perfect square "coins"

---

## Session Progression

The candidate progressed steadily through test-ownership levels, showing growing confidence and independence in both test design and implementation.

| Cycle | What Was Tested | Test Ownership Level | Hint Level | Pattern Checkpoint | Notes |
| ----- | --------------------------------------------- | --------------------- | ---------- | ------------------ | ------------------------------------------------------------------------------- |
| 1 | Base case (amount = 0) | L1 (Test Intent) | 0 | PASS | Simple base case, good starting point |
| 2 | Impossible case (coins=[2], amount=3) | L1 (Test Intent) | 1 | PASS (after Q&A) | Full DP implementation; debugging cycle for initialization bug (MIN → -1 → MAX) |
| 3 | Optimal solution (coins=[1,2,5], amount=11) | L2 (Assertion Sketch) | 0 | N/A | Test already passed (implementation complete from cycle 2) |
| 4 | Impossible odd amount (coins=[2,4], amount=7) | L3 (Learner-Authored) | 0 | N/A | Candidate wrote full test independently |

---

## No-Hire Trigger Check

- **Critical Triggers Observed:** None
- **Recovery Evidence:** N/A — no critical triggers occurred
- **Guardrail Applied:** None

The candidate did not exhibit any of the critical triggers:

- ✅ Explained the core invariant (`dp[i]` = minimum coins for amount `i`) correctly
- ✅ Did not need Level 3 hints for core algorithm logic
- ✅ Explained final time/space complexity (with correction)
- ✅ Could justify why the solution is correct (DP recurrence builds optimal solutions)
- ✅ Debugging was methodical and converged on the correct fix
- ✅ No critical bugs left unresolved at session end

---

## Overall Assessment

**Interview Recommendation:** Recommend
**Hiring Decision:** Hire
**Would Move Forward to Next Round:** Yes
**Confidence:** High

**Summary:**
The candidate successfully solved a medium-difficulty dynamic programming problem with minimal guidance. They identified the correct pattern, derived the recurrence relation, and implemented a clean solution. The initialization bug in cycle 2 was concerning but the candidate debugged it methodically with hints and arrived at the correct fix. Communication was strong, especially in asking clarifying questions about constraints and complexity nuances. I would move forward with this candidate to the next interview round.

**Strengths to Build On:**

- Asking about constraints and edge cases before diving into implementation
- Clear articulation of the DP pattern and state structure
- Methodical debugging approach when issues arise
- Strong test design (strategic, incremental, clear naming)

**Priority Areas for Growth:**

- **Mental simulation before coding:** Trace through a simple example manually to catch initialization bugs before running tests
- **Complexity analysis precision:** Be careful to distinguish between O(n²) and O(n × m) when loops iterate over different variables
- **Recurrence relation clarity:** Practice stating DP recurrences precisely upfront to reduce back-and-forth

**Recommended Next Steps:**

- Practice more unbounded knapsack problems to solidify the pattern (Coin Change II, Combination Sum IV, Perfect Squares)
- For each DP problem, write out the recurrence relation explicitly before coding
- Practice analyzing multi-variable time complexity (e.g., O(n × m), O(n × k × m)) to avoid O(n²) misclassifications

---
51 changes: 51 additions & 0 deletions leetcode/medium/0322-coin-change/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# [322. Coin Change](https://leetcode.com/problems/coin-change/)

![Medium](https://img.shields.io/badge/Medium-orange)

## Problem Description

You are given an integer array `coins` representing coins of different denominations and an integer `amount` representing a total amount of money.

Return the **fewest number of coins** that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return `-1`.

You may assume that you have an **infinite number** of each kind of coin.

## Examples

### Example 1

**Input:** `coins = [1,2,5]`, `amount = 11`

**Output:** `3`

**Explanation:** 11 = 5 + 5 + 1

### Example 2

**Input:** `coins = [2]`, `amount = 3`

**Output:** `-1`

**Explanation:** Cannot form 3 using only coin 2.

### Example 3

**Input:** `coins = [1]`, `amount = 0`

**Output:** `0`

**Explanation:** Zero amount requires zero coins.

### Example 4

**Input:** `coins = [2,4]`, `amount = 7`

**Output:** `-1`

**Explanation:** Impossible to form odd amount using only even-valued coins.

## Constraints

- `1 <= coins.length <= 12`
- `1 <= coins[i] <= 2^31 - 1`
- `0 <= amount <= 10^4`
20 changes: 20 additions & 0 deletions leetcode/medium/0322-coin-change/coin-change.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { describe, it, expect } from 'vitest';
import { coinChange } from './coin-change';

describe('Coin Change', () => {
it('should return 0 when amount is 0', () => {
expect(coinChange([1], 0)).toBe(0);
});

it('should return -1 when amount cannot be made with available coins', () => {
expect(coinChange([2], 3)).toBe(-1);
});

it('should return the minimum number of coins needed for a valid amount', () => {
expect(coinChange([1, 2, 5], 11)).toBe(3);
});

it('should return -1 when amount cannot be made with multiple available coins', () => {
expect(coinChange([2, 4], 7)).toBe(-1);
});
});
18 changes: 18 additions & 0 deletions leetcode/medium/0322-coin-change/coin-change.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export function coinChange(coins: number[], amount: number): number {
if (amount === 0) {
return 0;
}

const dp = Array.from({ length: amount + 1 }, () => Number.MAX_SAFE_INTEGER);
dp[0] = 0;

for (let i = 1; i <= amount; i++) {
for (const coin of coins) {
if (i - coin >= 0) {
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
}
}
}

return dp[amount] === Number.MAX_SAFE_INTEGER ? -1 : dp[amount];
}
Loading