120 lines
3.9 KiB
YAML
120 lines
3.9 KiB
YAML
title: 3Sum
|
|
slug: three-sum
|
|
difficulty: medium
|
|
leetcode_id: 15
|
|
leetcode_url: https://leetcode.com/problems/3sum/
|
|
categories:
|
|
- arrays
|
|
- two-pointers
|
|
- sorting
|
|
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.
|
|
|
|
Notice that the solution set must not contain duplicate triplets.
|
|
|
|
constraints: |
|
|
- 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."
|
|
- 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:
|
|
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.
|
|
|
|
Sorting enables two things: efficient two-pointer search and easy duplicate skipping.
|
|
We skip duplicates by checking if current value equals previous value.
|
|
|
|
common_pitfalls:
|
|
- title: Not handling duplicates
|
|
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"
|
|
|
|
- title: Wrong pointer skipping
|
|
description: |
|
|
After finding a valid triplet, skip duplicates for both left and right pointers
|
|
while maintaining left < right.
|
|
|
|
- title: Starting i too late
|
|
description: |
|
|
The outer loop should start at index 0. Also, skip if nums[i] > 0 since
|
|
sorted array means no valid triplet possible.
|
|
|
|
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
|
|
|
|
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).
|
|
|
|
solutions:
|
|
- approach_name: Sort + Two Pointers (Optimal)
|
|
is_optimal: true
|
|
code: |
|
|
def three_sum(nums: list[int]) -> list[list[int]]:
|
|
nums.sort()
|
|
result = []
|
|
|
|
for i in range(len(nums) - 2):
|
|
# Skip duplicates for i
|
|
if i > 0 and nums[i] == nums[i - 1]:
|
|
continue
|
|
|
|
# Early termination
|
|
if nums[i] > 0:
|
|
break
|
|
|
|
left, right = i + 1, len(nums) - 1
|
|
|
|
while left < right:
|
|
total = nums[i] + nums[left] + nums[right]
|
|
|
|
if total < 0:
|
|
left += 1
|
|
elif total > 0:
|
|
right -= 1
|
|
else:
|
|
result.append([nums[i], nums[left], nums[right]])
|
|
|
|
# Skip duplicates for left and right
|
|
while left < right and nums[left] == nums[left + 1]:
|
|
left += 1
|
|
while left < right and nums[right] == nums[right - 1]:
|
|
right -= 1
|
|
|
|
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.
|