feat(content): test cases batch 2
This commit is contained in:
@@ -11,109 +11,159 @@ patterns:
|
||||
- two-pointers
|
||||
|
||||
description: |
|
||||
Given an integer array `nums`, return all the triplets [nums[i], nums[j], nums[k]] such that
|
||||
i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0.
|
||||
Given an integer array `nums`, return all the triplets `[nums[i], nums[j], nums[k]]` such that `i != j`, `i != k`, and `j != k`, and `nums[i] + nums[j] + nums[k] == 0`.
|
||||
|
||||
Notice that the solution set must not contain duplicate triplets.
|
||||
Notice that the solution set must **not contain duplicate triplets**.
|
||||
|
||||
constraints: |
|
||||
- 3 <= nums.length <= 3000
|
||||
- -10^5 <= nums[i] <= 10^5
|
||||
- `3 <= nums.length <= 3000`
|
||||
- `-10^5 <= nums[i] <= 10^5`
|
||||
|
||||
examples:
|
||||
- input: "nums = [-1,0,1,2,-1,-4]"
|
||||
output: "[[-1,-1,2],[-1,0,1]]"
|
||||
explanation: "The distinct triplets that sum to zero."
|
||||
explanation: "The distinct triplets that sum to zero are [-1,-1,2] and [-1,0,1]."
|
||||
- input: "nums = [0,1,1]"
|
||||
output: "[]"
|
||||
explanation: "No triplet sums to zero."
|
||||
- input: "nums = [0,0,0]"
|
||||
output: "[[0,0,0]]"
|
||||
explanation: "Only one triplet sums to zero."
|
||||
explanation: "The only triplet [0,0,0] sums to zero."
|
||||
|
||||
explanation:
|
||||
approach: |
|
||||
1. Sort the array
|
||||
2. For each element nums[i], find pairs that sum to -nums[i]
|
||||
3. Use two pointers (left, right) to find pairs in the remaining array
|
||||
4. Skip duplicates at each level to avoid duplicate triplets
|
||||
|
||||
intuition: |
|
||||
After sorting, for each fixed element nums[i], we need to find nums[j] + nums[k] = -nums[i].
|
||||
This reduces to the Two Sum II problem on a sorted array, solvable with two pointers.
|
||||
Finding three numbers that sum to zero seems complex, but we can reduce it to a simpler problem we already know how to solve.
|
||||
|
||||
Sorting enables two things: efficient two-pointer search and easy duplicate skipping.
|
||||
We skip duplicates by checking if current value equals previous value.
|
||||
Think of it like this: if we **fix** one number (call it `a`), then we need to find two numbers that sum to `-a`. This is exactly the Two Sum problem! But instead of using a hash map (which makes duplicate handling tricky), we can use two pointers on a **sorted** array.
|
||||
|
||||
Sorting gives us two superpowers:
|
||||
1. **Two pointers work**: With a sorted array, if our sum is too small, move left pointer right; if too big, move right pointer left
|
||||
2. **Easy duplicate skipping**: Adjacent duplicates become neighbours, so `if nums[i] == nums[i-1]: skip`
|
||||
|
||||
The algorithm: for each element `nums[i]`, use two pointers on the remaining array to find pairs summing to `-nums[i]`.
|
||||
|
||||
approach: |
|
||||
We solve this using **Sort + Two Pointers**:
|
||||
|
||||
**Step 1: Sort the array**
|
||||
|
||||
- Sorting enables two-pointer technique and easy duplicate detection
|
||||
- Time: O(n log n), which doesn't affect overall O(n²) complexity
|
||||
|
||||
|
||||
|
||||
**Step 2: Fix the first element and find pairs**
|
||||
|
||||
- For each `i` from 0 to n-3:
|
||||
- Skip if `nums[i] == nums[i-1]` (avoid duplicate triplets)
|
||||
- **Early termination**: If `nums[i] > 0`, stop — no triplet can sum to zero (all remaining elements are positive)
|
||||
- Set `left = i + 1`, `right = n - 1`
|
||||
- Find pairs using two pointers
|
||||
|
||||
|
||||
|
||||
**Step 3: Two-pointer search for each fixed element**
|
||||
|
||||
- Calculate `total = nums[i] + nums[left] + nums[right]`
|
||||
- If `total < 0`: we need larger values, move `left` right
|
||||
- If `total > 0`: we need smaller values, move `right` left
|
||||
- If `total == 0`: found a triplet!
|
||||
- Add `[nums[i], nums[left], nums[right]]` to result
|
||||
- Skip duplicates for both pointers: `while nums[left] == nums[left+1]: left++`
|
||||
- Move both pointers inward
|
||||
|
||||
|
||||
|
||||
**Step 4: Return all unique triplets**
|
||||
|
||||
Duplicate skipping happens at three levels: the outer loop, left pointer, and right pointer.
|
||||
|
||||
common_pitfalls:
|
||||
- title: Not handling duplicates
|
||||
- title: Not Handling Duplicates Properly
|
||||
description: |
|
||||
Without duplicate skipping, you'll return duplicate triplets.
|
||||
Skip at the outer loop and both pointers.
|
||||
wrong_approach: "Not skipping when nums[i] == nums[i-1]"
|
||||
correct_approach: "if i > 0 and nums[i] == nums[i-1]: continue"
|
||||
Without careful duplicate skipping, you'll return duplicate triplets like `[-1,-1,2]` multiple times.
|
||||
|
||||
- title: Wrong pointer skipping
|
||||
description: |
|
||||
After finding a valid triplet, skip duplicates for both left and right pointers
|
||||
while maintaining left < right.
|
||||
Duplicates must be handled at **all three levels**:
|
||||
1. Outer loop: `if i > 0 and nums[i] == nums[i-1]: continue`
|
||||
2. Left pointer: `while left < right and nums[left] == nums[left+1]: left += 1`
|
||||
3. Right pointer: `while left < right and nums[right] == nums[right-1]: right -= 1`
|
||||
wrong_approach: "Using a set of tuples (works but slower)"
|
||||
correct_approach: "Skip adjacent duplicates at each level"
|
||||
|
||||
- title: Starting i too late
|
||||
- title: Duplicate Skipping Order After Finding Triplet
|
||||
description: |
|
||||
The outer loop should start at index 0. Also, skip if nums[i] > 0 since
|
||||
sorted array means no valid triplet possible.
|
||||
After finding a valid triplet, skip duplicates **before** moving both pointers. A common bug is skipping duplicates incorrectly, leading to missing triplets or infinite loops.
|
||||
|
||||
The sequence should be: (1) add triplet, (2) skip left duplicates, (3) skip right duplicates, (4) move both `left++` and `right--`.
|
||||
wrong_approach: "Moving pointers before skipping duplicates"
|
||||
correct_approach: "Skip duplicates first, then move both pointers"
|
||||
|
||||
- title: Missing Early Termination
|
||||
description: |
|
||||
Once `nums[i] > 0` in a sorted array, no valid triplet can exist (all remaining elements are non-negative, so the smallest possible sum is positive).
|
||||
|
||||
This optimisation can significantly speed up cases with many positive numbers.
|
||||
wrong_approach: "Continuing to search when nums[i] > 0"
|
||||
correct_approach: "if nums[i] > 0: break"
|
||||
|
||||
key_takeaways:
|
||||
- Reduce N-sum to (N-1)-sum by fixing one element
|
||||
- Sorting enables two-pointer approach and duplicate handling
|
||||
- Duplicate skipping happens at multiple levels
|
||||
- Time complexity is O(n²) — can't do better for returning all triplets
|
||||
- "**Reduce N-sum to (N-1)-sum**: Fix one element and solve a smaller problem — this pattern extends to 4Sum, kSum"
|
||||
- "**Sorting enables two pointers**: Transforms O(n²) lookup per element into O(n)"
|
||||
- "**Multi-level duplicate handling**: When returning all unique solutions, handle duplicates at every decision point"
|
||||
- "**Time complexity is O(n²)**: Can't do better when returning all triplets (there can be O(n²) triplets)"
|
||||
|
||||
time_complexity: "O(n²)"
|
||||
space_complexity: "O(log n) to O(n)"
|
||||
complexity_explanation: |
|
||||
Time: O(n log n) for sorting + O(n²) for the two-pointer search.
|
||||
Space: Depends on sorting algorithm (log n for in-place, n for non-in-place).
|
||||
time_complexity: "O(n²). Sorting is O(n log n), then for each of n elements, the two-pointer search is O(n)."
|
||||
space_complexity: "O(log n) to O(n). Depends on the sorting algorithm — O(log n) for in-place sorts, O(n) for others. The output is not counted as extra space."
|
||||
|
||||
solutions:
|
||||
- approach_name: Sort + Two Pointers (Optimal)
|
||||
- approach_name: Sort + Two Pointers
|
||||
is_optimal: true
|
||||
code: |
|
||||
def three_sum(nums: list[int]) -> list[list[int]]:
|
||||
nums.sort()
|
||||
nums.sort() # Enable two pointers and duplicate detection
|
||||
result = []
|
||||
n = len(nums)
|
||||
|
||||
for i in range(len(nums) - 2):
|
||||
# Skip duplicates for i
|
||||
for i in range(n - 2):
|
||||
# Skip duplicates for the first element
|
||||
if i > 0 and nums[i] == nums[i - 1]:
|
||||
continue
|
||||
|
||||
# Early termination
|
||||
# Early termination: if smallest element is positive, no solution
|
||||
if nums[i] > 0:
|
||||
break
|
||||
|
||||
left, right = i + 1, len(nums) - 1
|
||||
# Two pointers for the remaining array
|
||||
left, right = i + 1, n - 1
|
||||
|
||||
while left < right:
|
||||
total = nums[i] + nums[left] + nums[right]
|
||||
|
||||
if total < 0:
|
||||
# Need larger sum, move left pointer
|
||||
left += 1
|
||||
elif total > 0:
|
||||
# Need smaller sum, move right pointer
|
||||
right -= 1
|
||||
else:
|
||||
# Found a triplet
|
||||
result.append([nums[i], nums[left], nums[right]])
|
||||
|
||||
# Skip duplicates for left and right
|
||||
# Skip duplicates for left pointer
|
||||
while left < right and nums[left] == nums[left + 1]:
|
||||
left += 1
|
||||
# Skip duplicates for right pointer
|
||||
while left < right and nums[right] == nums[right - 1]:
|
||||
right -= 1
|
||||
|
||||
# Move both pointers for next pair
|
||||
left += 1
|
||||
right -= 1
|
||||
|
||||
return result
|
||||
explanation: |
|
||||
Fix one element and use two pointers to find the other two.
|
||||
Skip duplicates at all levels to avoid duplicate triplets.
|
||||
**Time Complexity:** O(n²) — O(n log n) sort + O(n) two-pointer search for each of O(n) elements.
|
||||
|
||||
**Space Complexity:** O(log n) to O(n) — Sorting space; output not counted.
|
||||
|
||||
We sort the array, then for each element, use two pointers to find pairs that complete the triplet. Careful duplicate skipping at all three levels ensures we return only unique triplets.
|
||||
|
||||
Reference in New Issue
Block a user