-
Notifications
You must be signed in to change notification settings - Fork 0
learn: solve 3Sum (#15) via guided TDD #230
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6068730
a767006
d6225a4
34ff89d
3657e0f
af2156f
5e3eb90
ff357cc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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', () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('should return multiple arrays with same value', () => { | |
| it('should de-duplicate triplets when multiple zeros are present', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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).
| 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
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * 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
AI
Feb 9, 2026
There was a problem hiding this comment.
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.
| * 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
AI
Feb 9, 2026
There was a problem hiding this comment.
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.
| const sortedArray = nums.sort((a, b) => a - b); | |
| const sortedArray = nums.slice().sort((a, b) => a - b); |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
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.
| const result = []; | |
| const result: number[][] = []; |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
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.
| 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
AI
Feb 9, 2026
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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].
There was a problem hiding this comment.
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.
| 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).
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
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.
| threeSum([-4, -1, -1, 0, 1, 2]); |
| 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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Skipping duplicate Line 103 frames this as a performance improvement, but it's actually needed for correctness. Without it, inputs like 🤖 Prompt for AI Agents |
||
|
|
||
| --- | ||
|
|
||
| ## 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)). | | ||
|
|
||
| --- | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| # 3Sum | ||
|
|
||
| **Difficulty:**  | ||
|
|
||
| [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` |
There was a problem hiding this comment.
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.