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 @@ -122,6 +122,7 @@ Complete list of all solved problems, organized by difficulty and topic.

- [0003 - Longest Substring Without Repeating Characters](../leetcode/medium/0003-longest-substring-without-repeating-characters) ![Medium](https://img.shields.io/badge/Medium-orange)
- [0011 - Container With Most Water](../leetcode/medium/0011-container-with-most-water) ![Medium](https://img.shields.io/badge/Medium-orange)
- [0015 - 3Sum](../leetcode/medium/0015-3sum) ![Medium](https://img.shields.io/badge/Medium-orange)
- [0016 - 3Sum Closest](../leetcode/medium/0016-3sum-closest) ![Medium](https://img.shields.io/badge/Medium-orange)
- [0018 - 4Sum](../leetcode/medium/0018-4sum) ![Medium](https://img.shields.io/badge/Medium-orange)
- [0031 - Next Permutation](../leetcode/medium/0031-next-permutation) ![Medium](https://img.shields.io/badge/Medium-orange)
Expand Down Expand Up @@ -261,6 +262,7 @@ Complete list of all solved problems, organized by difficulty and topic.
### Two Pointers

- [0011 - Container With Most Water](../leetcode/medium/0011-container-with-most-water) - Medium
- [0015 - 3Sum](../leetcode/medium/0015-3sum) - Medium
- [0016 - 3Sum Closest](../leetcode/medium/0016-3sum-closest) - Medium
- [0018 - 4Sum](../leetcode/medium/0018-4sum) - Medium
- [0080 - Remove Duplicates from Sorted Array II](../leetcode/medium/0080-remove-duplicates-from-sorted-array-ii) - Medium
Expand Down
49 changes: 49 additions & 0 deletions leetcode/medium/0015-3sum/3sum.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { describe, it, expect } from 'vitest';
import { threeSum } from './3sum';

describe('3Sum', () => {
it('should find all triplets that sum to zero for basic case', () => {
const nums = [-1, 0, 1, 2, -1, -4];
const result = threeSum(nums);
expect(result).toEqual([
[-1, -1, 2],
[-1, 0, 1]
]);
Comment on lines +8 to +11

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3Sum output order is not guaranteed by the problem; asserting a specific array ordering can make tests brittle even if the solution is correct. Consider normalizing (sort triplets and sort the list of triplets) before comparing, or compare as an unordered set-like structure.

Copilot uses AI. Check for mistakes.
});

it('should return empty array when no triplets sum to zero', () => {
const nums = [0, 1, 1];
const result = threeSum(nums);
expect(result).toEqual([]);
});

it('should handle array of all zeros', () => {
const nums = [0, 0, 0];
const result = threeSum(nums);
expect(result).toEqual([[0, 0, 0]]);
});

it('should return empty array for empty input', () => {
const nums: number[] = [];
const result = threeSum(nums);
expect(result).toEqual([]);
});

it('should return empty array for array with fewer than 3 elements', () => {
const nums = [1, 2];
const result = threeSum(nums);
expect(result).toEqual([]);
});

it('should return empty array for all positive numbers', () => {
const nums = [1, 2, 3];
const result = threeSum(nums);
expect(result).toEqual([]);
});

it('should return multiple arrays with same value', () => {

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test name is unclear/misleading: the expectation asserts a single triplet [[0, 0, 0]]. Consider renaming to reflect the intent (e.g., handling many duplicate zeros / ensuring de-duplication of triplets).

Suggested change
it('should return multiple arrays with same value', () => {
it('should de-duplicate triplets when multiple zeros are present', () => {

Copilot uses AI. Check for mistakes.
const nums = [1, 2, 0, 1, 0, 0, 0, 0];
const result = threeSum(nums);
expect(result).toEqual([[0, 0, 0]]);
});
});
Comment on lines +4 to +49

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add a test case with duplicate pairs to catch missing inner-loop dedup.

The current tests don't exercise the scenario where duplicate left/right values produce duplicate triplets. For example, [-2, 0, 0, 2, 2] should return [[-2, 0, 2]] but the current implementation would return it twice. Adding such a test will expose the bug in the solution.

Proposed additional test case
+  it('should not return duplicate triplets when inner values repeat', () => {
+    const nums = [-2, 0, 0, 2, 2];
+    const result = threeSum(nums);
+    expect(result).toEqual([[-2, 0, 2]]);
+  });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
describe('3Sum', () => {
it('should find all triplets that sum to zero for basic case', () => {
const nums = [-1, 0, 1, 2, -1, -4];
const result = threeSum(nums);
expect(result).toEqual([
[-1, -1, 2],
[-1, 0, 1]
]);
});
it('should return empty array when no triplets sum to zero', () => {
const nums = [0, 1, 1];
const result = threeSum(nums);
expect(result).toEqual([]);
});
it('should handle array of all zeros', () => {
const nums = [0, 0, 0];
const result = threeSum(nums);
expect(result).toEqual([[0, 0, 0]]);
});
it('should return empty array for empty input', () => {
const nums: number[] = [];
const result = threeSum(nums);
expect(result).toEqual([]);
});
it('should return empty array for array with fewer than 3 elements', () => {
const nums = [1, 2];
const result = threeSum(nums);
expect(result).toEqual([]);
});
it('should return empty array for all positive numbers', () => {
const nums = [1, 2, 3];
const result = threeSum(nums);
expect(result).toEqual([]);
});
});
describe('3Sum', () => {
it('should find all triplets that sum to zero for basic case', () => {
const nums = [-1, 0, 1, 2, -1, -4];
const result = threeSum(nums);
expect(result).toEqual([
[-1, -1, 2],
[-1, 0, 1]
]);
});
it('should return empty array when no triplets sum to zero', () => {
const nums = [0, 1, 1];
const result = threeSum(nums);
expect(result).toEqual([]);
});
it('should handle array of all zeros', () => {
const nums = [0, 0, 0];
const result = threeSum(nums);
expect(result).toEqual([[0, 0, 0]]);
});
it('should return empty array for empty input', () => {
const nums: number[] = [];
const result = threeSum(nums);
expect(result).toEqual([]);
});
it('should return empty array for array with fewer than 3 elements', () => {
const nums = [1, 2];
const result = threeSum(nums);
expect(result).toEqual([]);
});
it('should return empty array for all positive numbers', () => {
const nums = [1, 2, 3];
const result = threeSum(nums);
expect(result).toEqual([]);
});
it('should not return duplicate triplets when inner values repeat', () => {
const nums = [-2, 0, 0, 2, 2];
const result = threeSum(nums);
expect(result).toEqual([[-2, 0, 2]]);
});
});
🤖 Prompt for AI Agents
In `@leetcode/medium/0015-3sum/3sum.test.ts` around lines 4 - 43, Add a unit test
that ensures duplicate left/right values don't produce duplicate triplets: in
the test suite for threeSum add a case calling threeSum with nums = [-2, 0, 0,
2, 2] and assert the result equals [[-2, 0, 2]]; this targets the inner-loop
dedup logic in the threeSum implementation (look for the two-pointer section
where left/right are advanced and ensure duplicate-skipping is exercised).

52 changes: 52 additions & 0 deletions leetcode/medium/0015-3sum/3sum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
*
* What algorithmic pattern applies to this problem?
* A. Two pointer pattern that will allow to reduce nested loops that cause O(n2) time
* What variables will you need to track as you iterate?
* A. A left pointer, a right pointer, current item in nums, and a results array
* What property must remain true throughout your algorithm?
* A. The total must not go below 0 for any of the current values of the variables left, right, current
*
* Time and Space complexity
* @time - O(n2) because of the inner while loop that runs for each element in the sortedArray
* @space = O(n2) for each array inside of the result array
Comment on lines +4 to +12

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doc comment has incorrect/misleading statements: (1) the invariant about the total not going below 0 is not true for 3Sum (negative sums are part of the search); (2) space complexity is not O(n²) as written—auxiliary space is O(1) excluding output; (3) prefer standard notation O(n^2) for readability.

Suggested change
* A. Two pointer pattern that will allow to reduce nested loops that cause O(n2) time
* What variables will you need to track as you iterate?
* A. A left pointer, a right pointer, current item in nums, and a results array
* What property must remain true throughout your algorithm?
* A. The total must not go below 0 for any of the current values of the variables left, right, current
*
* Time and Space complexity
* @time - O(n2) because of the inner while loop that runs for each element in the sortedArray
* @space = O(n2) for each array inside of the result array
* A. Two-pointer pattern on a sorted array that reduces the brute-force O(n^3) search to O(n^2) time.
* What variables will you need to track as you iterate?
* A. A left pointer, a right pointer, current item in nums, and a results array.
* What property must remain true throughout your algorithm?
* A. The array remains sorted and the left and right pointers move inward (left++ when sum < 0, right-- when sum > 0), while skipping duplicates to avoid duplicate triplets.
*
* Time and Space complexity
* @time - O(n^2) because of the inner while loop that runs for each element in the sortedArray.
* @space - O(1) auxiliary space (excluding the O(k) space needed to store the resulting triplets).

Copilot uses AI. Check for mistakes.
Comment on lines +4 to +12

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doc comment has incorrect/misleading statements: (1) the invariant about the total not going below 0 is not true for 3Sum (negative sums are part of the search); (2) space complexity is not O(n²) as written—auxiliary space is O(1) excluding output; (3) prefer standard notation O(n^2) for readability.

Suggested change
* A. Two pointer pattern that will allow to reduce nested loops that cause O(n2) time
* What variables will you need to track as you iterate?
* A. A left pointer, a right pointer, current item in nums, and a results array
* What property must remain true throughout your algorithm?
* A. The total must not go below 0 for any of the current values of the variables left, right, current
*
* Time and Space complexity
* @time - O(n2) because of the inner while loop that runs for each element in the sortedArray
* @space = O(n2) for each array inside of the result array
* A. Two pointer pattern that will allow to reduce nested loops that cause O(n^2) time
* What variables will you need to track as you iterate?
* A. A left pointer, a right pointer, current item in nums, and a results array
* What property must remain true throughout your algorithm?
* A. The array remains sorted, the two pointers move inward while left < right, and no duplicate triplets are added to the result.
*
* Time and Space complexity
* @time - O(n^2) because of the inner while loop that runs for each element in the sortedArray
* @space - O(1) auxiliary space (excluding the output; storing the result triplets takes O(k) space for k triplets)

Copilot uses AI. Check for mistakes.
*/
export function threeSum(nums: number[]): number[][] {
const sortedArray = nums.sort((a, b) => a - b);

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorting nums in-place mutates the caller’s input array. If this function is intended to be a pure utility, make a copy before sorting (e.g., clone then sort) to avoid surprising API behavior.

Suggested change
const sortedArray = nums.sort((a, b) => a - b);
const sortedArray = nums.slice().sort((a, b) => a - b);

Copilot uses AI. Check for mistakes.
const result = [];

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In TypeScript, const result = [] will default to any[] in many configurations, losing type safety. Explicitly type this as number[][] (or initialize in a way that preserves the intended type) to keep strong typing through push and return.

Suggested change
const result = [];
const result: number[][] = [];

Copilot uses AI. Check for mistakes.

for (let i = 0; i < sortedArray.length; i++) {

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The outer loop can stop at sortedArray.length - 2 (since you need at least 3 elements), and you can break early once sortedArray[i] > 0 because all remaining values are ≥ sortedArray[i] in a sorted array, so no triplet can sum to zero. This reduces unnecessary iterations on larger inputs.

Suggested change
for (let i = 0; i < sortedArray.length; i++) {
for (let i = 0; i < sortedArray.length - 2; i++) {
// Since the array is sorted, once the fixed element is > 0, no triplet can sum to 0
if (sortedArray[i] > 0) {
break;
}

Copilot uses AI. Check for mistakes.
// Skip duplicate values for the fixed element to avoid duplicate triplets
if (i > 0 && sortedArray[i] === sortedArray[i - 1]) {
continue;
}

let left = i + 1;
let right = sortedArray.length - 1;
Comment on lines +24 to +25

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The outer loop can stop at sortedArray.length - 2 (since you need at least 3 elements), and you can break early once sortedArray[i] > 0 because all remaining values are ≥ sortedArray[i] in a sorted array, so no triplet can sum to zero. This reduces unnecessary iterations on larger inputs.

Copilot uses AI. Check for mistakes.

while (left < right) {
const sum = sortedArray[i] + sortedArray[left] + sortedArray[right];
if (sum === 0) {
result.push([sortedArray[i], sortedArray[left], sortedArray[right]]);
left++;
right--;
Comment on lines +29 to +32

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Skip duplicate pairs after a match to avoid repeat triplets

When a zero-sum triplet is found, the code just increments left and decrements right once, but it does not skip over subsequent equal values. On inputs with repeated values (e.g., [-2,0,0,2,2]), this produces duplicate triplets like [-2,0,2] twice, which violates the problem requirement of unique triplets. Consider advancing left/right past duplicates after pushing a match so each unique pair is emitted once.

Useful? React with 👍 / 👎.

Comment on lines +29 to +32

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Bug: Missing duplicate skipping for left/right pointers produces duplicate triplets.

After finding a valid triplet, the code advances left++ and right-- but doesn't skip over consecutive duplicate values. For input [-2, 0, 0, 2, 2], this will push [-2, 0, 2] twice.

Proposed fix
       if (sum === 0) {
         result.push([sortedArray[i], sortedArray[left], sortedArray[right]]);
-        left++;
-        right--;
+        // Skip duplicate left values
+        while (left < right && sortedArray[left] === sortedArray[left + 1]) left++;
+        // Skip duplicate right values
+        while (left < right && sortedArray[right] === sortedArray[right - 1]) right--;
+        left++;
+        right--;
       } else if (sum < 0) {

Based on learnings: "Check for two-pointer technique correctness" and "Verify the solution correctly solves the problem for all test cases, including edge cases."

🤖 Prompt for AI Agents
In `@leetcode/medium/0015-3sum/3sum.ts` around lines 29 - 32, The three-sum
implementation pushes a valid triplet when sum === 0 but only does left++ and
right--, which allows duplicate triplets for repeated values; inside the block
handling sum === 0 in the function (using sortedArray, left, right, result and
loop variable i) add duplicate-skipping loops: after incrementing left and
decrementing right, advance left while left < right and sortedArray[left] ===
sortedArray[left - 1], and similarly decrement right while left < right and
sortedArray[right] === sortedArray[right + 1]; also ensure the outer loop over i
skips duplicate starting values by continuing when sortedArray[i] ===
sortedArray[i - 1].

// Skip duplicate values for left pointer
while (left < right && sortedArray[left] === sortedArray[left - 1]) {
left++;
}
// Skip duplicate values for right pointer
while (left < right && sortedArray[right] === sortedArray[right + 1]) {
right--;
}
} else if (sum < 0) {
left++;
} else {
right--;
}
}
}

return result;
}

threeSum([-4, -1, -1, 0, 1, 2]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove the stray direct invocation — likely a debug artifact.

This call executes every time the module is imported (including by tests) and has no side effect besides wasted computation. It could also cause confusion if the module is imported in a production context.

Proposed fix
-
-threeSum([-4, -1, -1, 0, 1, 2]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
threeSum([-4, -1, -1, 0, 1, 2]);
🤖 Prompt for AI Agents
In `@leetcode/medium/0015-3sum/3sum.ts` at line 44, The file contains a stray
direct invocation of the threeSum function (threeSum([-4, -1, -1, 0, 1, 2]))
that runs on import; remove this call so the function is only executed by tests
or callers, or alternatively wrap it in a top-level guard (e.g., an explicit
main/if-run block) so imports don't trigger execution; locate the literal call
to threeSum in the module and delete it (or move it into a non-import-executed
demo section).

Comment on lines +51 to +52

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This executes threeSum at module import time, which introduces an unwanted side effect (and can break consumers/tests if they import this file). Remove this call, or move it into a dedicated example runner / test.

Suggested change
threeSum([-4, -1, -1, 0, 1, 2]);

Copilot uses AI. Check for mistakes.
190 changes: 190 additions & 0 deletions leetcode/medium/0015-3sum/POST_MORTEM.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# Post-Mortem Log

## Problem

Find all unique triplets in an integer array that sum to zero. The challenge is to avoid duplicate triplets in the result while efficiently searching through potentially large arrays.

- **Problem Name:** 3Sum
- **Problem Link:** [LeetCode #15 - 3Sum](https://leetcode.com/problems/3sum/)
- **Date:** 2026-02-09

---

## Time Tracking

- **Time to design the algorithm:** ~15 minutes (through pattern checkpoint and guided questions)
- **Time to code:** ~20 minutes (6 TDD cycles with iterations)
- **Time debugging/fixing:** ~10 minutes (understanding nested loop structure and duplicate handling)

---

## Solution Exploration

### What approaches did I consider?

1. **Brute Force (O(n³))**: Three nested loops checking every possible triplet combination. Would work but too slow for large inputs (n ≤ 3000).

2. **Hash Map Approach (O(n²))**: For each pair, check if the complement exists in a hash set. More complex duplicate handling required.

3. **Sort + Two Pointers (O(n² + n log n) = O(n²))**: **Chosen approach**. Sort the array first, then for each element, use two pointers to find pairs that sum to the target. Sorting enables efficient duplicate skipping.

### Final Solution Analysis

- **Time Complexity:** O(n²)
- Sorting: O(n log n)
- Outer loop: O(n)
- Inner two-pointer scan: O(n) per iteration
- Total: O(n log n + n²) = O(n²)

- **Space Complexity:** O(1)
- Not counting the output array, only using constant extra space (pointers and sum variable)
- If counting output: O(k) where k is the number of triplets found

- **Is it optimal?** Yes. This is the optimal solution for the 3Sum problem. We cannot do better than O(n²) because we must examine at least n² pairs to find all valid triplets.

### Why this approach worked (or didn't)

The sort + two-pointers approach is optimal because:

- **Sorting enables systematic search**: After sorting, we can use the two-pointer technique to efficiently search for pairs
- **Early termination**: If `nums[i] > 0`, we can stop early (all remaining numbers are positive)
- **Duplicate avoidance**: In a sorted array, duplicates are adjacent, making them easy to skip
- **No extra space**: Unlike hash map approaches, we only use O(1) extra space

---

## Pattern Recognition

### What algorithmic pattern does this problem use?

**Two Pointers (Opposite Direction)** with a fixed element. More specifically, this uses the "Fixed Element + Two Pointers" variant:

- Outer loop fixes one element at position `i`
- Inner loop uses two pointers (`left` and `right`) to search the remaining sorted subarray for pairs that sum to `-nums[i]`

### Key Insight

The "aha moment" for 3Sum is realizing it's **not** a single two-pointer problem, but a **nested structure**: **3Sum = TwoSum repeated n times**.

For each fixed element `nums[i]`, we're essentially solving the TwoSum problem on the remaining array: "Find two numbers that sum to `-nums[i]`". Because the array is sorted, we can use the efficient two-pointer technique for each TwoSum subproblem.

**Duplicate handling insight**: "No duplicate triplets" means no duplicate _arrays_ in the result, not no duplicate _values_ within a triplet. We handle this by skipping consecutive duplicate values for the fixed element `i`.

### Related Problems

1. **LeetCode #1 - Two Sum**: The foundation - finding two numbers that sum to a target
2. **LeetCode #16 - 3Sum Closest**: Similar structure, but finding the triplet closest to a target instead of exactly zero
3. **LeetCode #18 - 4Sum**: Extends the pattern to four numbers (adds another outer loop)
4. **LeetCode #167 - Two Sum II (Sorted Array)**: The two-pointer technique used in the inner loop

---

## Edge Cases & Verification

### What clarifying questions did I ask?

(In coach mode, the pattern checkpoint questions served as clarifying questions)

- What pattern applies? (Two pointers with nested structure)
- What variables are needed? (i, left, right, result array)
- What invariant must hold? (Systematic search of sorted space)

### Edge cases handled

- ✅ **Empty array**: Returns `[]`
- ✅ **Array with fewer than 3 elements**: Returns `[]`
- ✅ **All zeros**: Returns `[[0, 0, 0]]`
- ✅ **No valid triplets**: Returns `[]` (e.g., `[0, 1, 1]` or all positive numbers)
- ✅ **Duplicate values in triplets**: Correctly includes triplets like `[-1, -1, 2]`
- ✅ **Duplicate triplets**: Correctly avoids adding the same triplet twice by skipping duplicate `i` values

### Edge cases missed

- ⚠️ **Optimization**: Could skip duplicate `left` and `right` values after finding a match for better performance on arrays with many duplicates
- ⚠️ **Early termination**: Could break early if `nums[i] > 0` (all remaining numbers are positive, so no triplet can sum to zero)
Comment on lines +103 to +104

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Skipping duplicate left/right is a correctness requirement, not just an optimization.

Line 103 frames this as a performance improvement, but it's actually needed for correctness. Without it, inputs like [-2, 0, 0, 2, 2] will produce [-2, 0, 2] twice in the result, violating the "no duplicate triplets" constraint. This should be moved from "Edge cases missed" to a required fix in the implementation.

🤖 Prompt for AI Agents
In `@leetcode/medium/0015-3sum/POST_MORTEM.md` around lines 103 - 104, The comment
is saying skipping duplicate left/right values after finding a valid triplet is
required for correctness (not just optimization); update the three-sum
implementation (the loop that uses left/right two-pointer logic over the sorted
nums array, e.g., the code around variables left, right, and i in the threeSum
function) so that after pushing a found triplet you advance left while
nums[left] == nums[left-1] and decrement right while nums[right] ==
nums[right+1] to avoid emitting identical triplets, and ensure you also move
left++ and right-- after those skips.


---

## Mistakes & Bugs

### Mistakes I keep making

1. **Misunderstanding "no duplicates"**: Initially confused "no duplicate triplets" with "no duplicate values within a triplet"
2. **Pointer initialization**: Started with `left = 1` instead of `left = i + 1`, causing incorrect results when `i > 0`
3. **Breaking too early**: Used `break` after finding one match, stopping the search prematurely instead of continuing to find all valid triplets
4. **Single-pass misunderstanding**: Tried to solve with a single two-pointer scan instead of nested structure (outer loop + inner two-pointer)

### Bugs to add to the Bug List

- **Bug**: Initializing pointers outside the loop and never resetting them
- **Fix**: Reset `left = i + 1` and `right = nums.length - 1` for each iteration of `i`
- **Bug**: Using `break` instead of moving both pointers after finding a match
- **Fix**: After finding a match, do `left++` and `right--` to continue searching
- **Bug**: Checking for duplicate values within a triplet instead of duplicate triplet arrays
- **Fix**: Skip duplicate `i` values with `if (i > 0 && nums[i] === nums[i-1]) continue`

---

## Retrospective

### Key Takeaways & Lessons Learned

1. **Nested two-pointer pattern**: Some problems require combining patterns - 3Sum is "fixed element + two pointers", not just "two pointers"

2. **Sorting as preprocessing**: Sorting (O(n log n)) is often worth it if it enables a more efficient main algorithm (O(n²) vs O(n³))

3. **Read requirements carefully**: "No duplicate triplets" ≠ "no duplicate values" - understanding the exact requirement is crucial

4. **TDD reveals understanding gaps**: The iterative testing process exposed conceptual misunderstandings early (like pointer initialization and loop structure)

5. **Coach mode effectiveness**: Writing code yourself (vs watching the Navigator) forces deeper understanding of the pattern

### Add to Cheat Sheet

**Two Pointers (Fixed Element + Search) Pattern:**

```typescript
// Sort first
nums.sort((a, b) => a - b);

for (let i = 0; i < nums.length; i++) {
// Skip duplicates for fixed element
if (i > 0 && nums[i] === nums[i - 1]) continue;

let left = i + 1;
let right = nums.length - 1;

while (left < right) {
const sum = nums[i] + nums[left] + nums[right];
if (sum === target) {
// Found match - move BOTH pointers
left++;
right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
```

**Key principles:**

- Reset pointers for each fixed element
- Move both pointers after finding a match
- Skip adjacent duplicates in sorted array

---

## Rubric Self-Rating (1–5)

| Category | Rating | Notes |
| ----------------------- | ------ | ----------------------------------------------------------------------------------------------------------- |
| **Problem solving** | 3/5 | Eventually identified the pattern, but struggled with nested structure initially. Needed Level 2 hints. |
| **Coding** | 4/5 | Code is clean and correct after iterations. Good variable names. Minor issues with pointer initialization. |
| **Verification** | 4/5 | Comprehensive test coverage (6 tests). Caught edge cases. Could have desk-checked logic earlier. |
| **Communication** | 3/5 | Pattern checkpoint answers showed partial understanding. Improved after guidance. Good code comments. |
| **Complexity Analysis** | 3/5 | Correctly identified O(n²) time. Space complexity explanation could be clearer (said O(n²), actually O(1)). |

---
47 changes: 47 additions & 0 deletions leetcode/medium/0015-3sum/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# 3Sum

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

[View on LeetCode](https://leetcode.com/problems/3sum/)

## Problem Description

Given an integer array `nums`, return all the triplets `[nums[i], nums[j], nums[k]]` where `nums[i] + nums[j] + nums[k] == 0`, and the indices `i`, `j`, and `k` are all distinct.

The output should not contain any duplicate triplets. You may return the output and the triplets in any order.

## Examples

**Example 1:**

```text
Input: nums = [-1,0,1,2,-1,-4]
Output: [[-1,-1,2],[-1,0,1]]
Explanation:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0.
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0.
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0.
The distinct triplets are [-1,0,1] and [-1,-1,2].
Notice that the order of the output and the order of the triplets does not matter.
```

**Example 2:**

```text
Input: nums = [0,1,1]
Output: []
Explanation: The only possible triplet does not sum up to 0.
```

**Example 3:**

```text
Input: nums = [0,0,0]
Output: [[0,0,0]]
Explanation: The only possible triplet sums up to 0.
```

## Constraints

- `0 <= nums.length <= 3000`
- `-10^5 <= nums[i] <= 10^5`
Loading