Coding ProblemsTwo PointersSorting
3Sum | Leetcode 15
Welcome to our deep dive on 3Sum (Leetcode 15). Expanding upon the popular Two Sum problem, 3Sum demands extreme duplicate management since we must return uniquely distinct triplets.
Problem Statement
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.
Example:
nums = [-1, 0, 1, 2, -1, -4] => Output: [[-1, -1, 2], [-1, 0, 1]]
Approach: Target Fixing + Two Pointers O(N^2)
The key to optimizing 3Sum without brute-forcing every combination O(N^3) is to rely on Sorting.
- Sort the array: Sorting allows us to easily skip duplicate values and use a highly efficient two-pointer squeeze on the remaining bounds.
- Anchor the target: Iterate through the array. For every
nums[i], anchor it as your target component. Crucially, ifnums[i] == nums[i-1], we skip it to prevent generating duplicate identical triplets! - Squeeze Pointers: Fire a
leftpointer just abovei, and arightpointer at the end of the array. Squeeze them inward based on whether the total sum is< 0or> 0. - Skip Internal Duplicates: When a valid triplet is found, we must also aggressively bump the
leftpointer to bypass any identical adjacent values to avoid duplicate outputs.
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
res = []
nums.sort()
for i in range(len(nums) - 2):
# Bypass duplicate anchor candidates
if i > 0 and nums[i] == nums[i - 1]:
continue
left = i + 1
right = len(nums) - 1
while left < right:
total = nums[i] + nums[left] + nums[right]
if total < 0:
left += 1
elif total > 0:
right -= 1
else:
res.append([nums[i], nums[left], nums[right]])
# Bypass duplicate internal bounds
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 res
Complexity Analysis
| Metric | Complexity | Explanation |
|---|---|---|
| Time | O(N²) | The array is sorted initially in O(N log N). Then, we execute an O(N) loop. Inside that loop, our two pointers scan the remaining N elements exactly once. Total time resolves natively to O(N²). |
| Space | O(1) | Constant internal execution memory space. |