3Sum
Find all unique triplets in an array that sum up to zero. The premier problem for learning how to combine sorting with two-pointer inward scans to avoid cubic brute force.
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.
Examples & Constraints
- 3 <= nums.length <= 3000
- -10^5 <= nums[i] <= 10^5
Sort & Two-Pointer Inward Scan
Optimal ApproachSort the array first. Fix the first element with an outer loop, then use two converging pointers to find pairs that sum to the target negation in O(n²) time.
Sorting takes O(n log n). The outer loop runs N times, and each two-pointer inner scan takes O(n). Total runtime is O(n log n + n²) = O(n²).
O(1) auxiliary space beyond the output array if in-place sorting is used, or O(n) for the sorting stack frames depending on language implementation.
Underlying algorithmic logic
Why Naive Brute Force Is Prohibitive
An exhaustive three-loop search evaluates all combinations in O(n³) time. For N = 3,000, 3000³ is 27,000,000,000 operations, which guarantees a timeout.
The Two-Pointer Reduction
If we sort the array first (O(n log n)), we can reduce the 3-variable problem into a sequence of sorted 2-variable problems:
- Sort `nums` in ascending order.
- Iterate
ifrom0ton - 3:
- Pruning: If
nums[i] > 0, terminate the outer loop immediately! Since the array is sorted, any subsequent positive numbers can never sum to zero. - Skip Outer Duplicates: If
i > 0andnums[i] == nums[i - 1], skip to prevent duplicate triplets. - Set
left = i + 1andright = n - 1.
- While
left < right:
- Calculate
sum = nums[i] + nums[left] + nums[right]. - If `sum == 0`: We found a valid triplet! Record
[nums[i], nums[left], nums[right]]. - Advance
left++while skipping any identical consecutive values (nums[left] == nums[left - 1]). - Decrement
right--while skipping any identical consecutive values (nums[right] == nums[right + 1]). - If `sum < 0`: The sum is too small. Advance
left++to increase value. - If `sum > 0`: The sum is too large. Decrement
right--to decrease value.
Handling Duplicates Without Extra Sets
The genius of sorting first is that duplicate numbers are clustered together. By explicitly skipping identical numbers at both the outer pivot i and the inner pointers (left and right), we guarantee zero duplicate triplets without wasting memory on an auxiliary hash set.
Step-by-step execution walkthrough
[-1, 0, 1, 2, -1, -4] sorted becomes [-4, -1, -1, 0, 1, 2].
Pointers at left = 1 (-1), right = 5 (2). Maximum possible sum is -4 + 1 + 2 = -1 < 0. No pair can reach 0 with -4.
left = 2 (-1), right = 5 (2). Sum: (-1) + (-1) + 2 = 0! Triplet [-1, -1, 2] recorded.
left = 3 (0), right = 4 (1). Sum: (-1) + 0 + 1 = 0! Triplet [-1, 0, 1] recorded.
- •Optimal O(n²) runtime
- •Zero memory waste by skipping duplicate values in-place
- •Mutates original array ordering (requires sorting)
Code Implementations
Ready-to-useCopy & paste production-ready solutions for Sort & Two-Pointer Inward Scan in your language of choice
def three_sum(nums: list[int]) -> list[list[int]]:nums.sort()res = []n = len(nums)for i in range(n - 2):if nums[i] > 0:breakif i > 0 and nums[i] == nums[i - 1]:continueleft, right = i + 1, n - 1while left < right:total = nums[i] + nums[left] + nums[right]if total == 0:res.append([nums[i], nums[left], nums[right]])left += 1right -= 1while left < right and nums[left] == nums[left - 1]:left += 1while left < right and nums[right] == nums[right + 1]:right -= 1elif total < 0:left += 1else:right -= 1return resif __name__ == "__main__":nums = [-1, 0, 1, 2, -1, -4]print("Unique Triplets:", three_sum(nums))
Understand Array & Matrix Visually
Explore sequential element access, subsegment manipulations, insertion, deletion, and 2D grid matrix walks. Test live edge cases and watch memory state transitions step-by-step.
Frequently Asked Questions
Related Logic & Algorithm Problems
Two Sum
Find the two numbers in an array that sum up to a target value. The quintessential problem for learning how to trade memory for speed using a Hash Map.
Valid Palindrome
Determine if a string is a palindrome considering only alphanumeric characters and ignoring case. The canonical problem for learning the two-pointer inward convergence technique.
Contains Duplicate
Determine if any value appears at least twice in an integer array. A foundational problem for mastering constant-time hash lookups vs sorting trade-offs.