0016. 3Sum Closest¶
Table of Contents¶
- Problem
- Problem Breakdown
- Approach 1: Brute Force
- Approach 2: Sort + Two Pointers
- Complexity Comparison
- Edge Cases
- Common Mistakes
- Related Problems
- Visual Animation
Problem¶
| Leetcode | 16. 3Sum Closest |
| Difficulty | 🟡 Medium |
| Tags | Array, Two Pointers, Sorting |
Description¶
Given an integer array
numsof lengthnand an integertarget, find three integers innumssuch that the sum is closest totarget.Return the sum of the three integers.
You may assume that each input would have exactly one solution.
Examples¶
Example 1:
Input: nums = [-1,2,1,-4], target = 1
Output: 2
Explanation: The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
Example 2:
Input: nums = [0,0,0], target = 1
Output: 0
Explanation: The sum that is closest to the target is 0. (0 + 0 + 0 = 0).
Example 3:
Input: nums = [1,1,1,0], target = 3
Output: 3
Explanation: The sum that equals the target is 3. (1 + 1 + 1 = 3).
Constraints¶
n == nums.length3 <= n <= 500-1000 <= nums[i] <= 1000-10^4 <= target <= 10^4
Problem Breakdown¶
1. What is being asked?¶
Given an array of integers and a target value, find the triplet whose sum is closest to the target. Unlike 3Sum (which finds exact matches equaling zero), here we need the minimum distance between any triplet sum and the target. Return the actual sum, not the distance.
2. What is the input?¶
| Parameter | Type | Description |
|---|---|---|
nums | int[] | Array of integers (may contain negatives, duplicates) |
target | int | The target value to get closest to |
Important observations about the input: - The array is not sorted - Elements can be negative, zero, or positive - The array always has at least 3 elements - Exactly one solution is guaranteed (no ties)
3. What is the output?¶
- A single integer — the sum of the three integers closest to
target - The closeness is measured by
|sum - target|
4. Constraints analysis¶
| Constraint | Significance |
|---|---|
n <= 500 | O(n^3) = 1.25 * 10^8 — borderline. O(n^2) is safe. |
nums[i] in [-1000, 1000] | Max sum = 3000, min sum = -3000. Fits in int32. |
target in [-10^4, 10^4] | Max distance = 10^4 + 3000 = 13000. Fits in int32. |
n >= 3 | Always at least one triplet to check |
| Exactly one solution | No need to handle ties |
5. Step-by-step example analysis¶
Example 1: nums = [-1, 2, 1, -4], target = 1¶
All possible triplets:
(-1, 2, 1) = 2 → |2 - 1| = 1
(-1, 2, -4) = -3 → |-3 - 1| = 4
(-1, 1, -4) = -4 → |-4 - 1| = 5
(2, 1, -4) = -1 → |-1 - 1| = 2
Closest sum: 2 (distance = 1)
Result: 2
Example 2: nums = [0, 0, 0], target = 1¶
Example 3: nums = [1, 1, 1, 0], target = 3¶
All possible triplets:
(1, 1, 1) = 3 → |3 - 3| = 0 ← exact match!
(1, 1, 0) = 2 → |2 - 3| = 1
(1, 1, 0) = 2 → |2 - 3| = 1
(1, 1, 0) = 2 → |2 - 3| = 1
Closest sum: 3 (exact match)
Result: 3
6. Key Observations¶
- Distance metric — We minimize
|sum - target|, wheresum = nums[i] + nums[j] + nums[k]. - Sorting helps — After sorting, we can use two pointers to efficiently search for the closest sum. If the current sum is too small, move the left pointer right; if too large, move the right pointer left.
- Early termination — If we find an exact match (
sum == target), we can return immediately since distance is 0. - Relationship to 3Sum — This is a generalization of 3Sum. Instead of checking
sum == 0, we track the minimum|sum - target|.
7. Pattern identification¶
| Pattern | Why it fits | Example |
|---|---|---|
| Sort + Two Pointers | O(n^2) scan with sorted array, directional movement | 3Sum, 3Sum Closest (this problem) |
| Brute Force | Always works, check all triplets | All problems |
Chosen pattern: Sort + Two Pointers Reason: Sorting the array allows us to use two pointers that move directionally based on whether the current sum is above or below the target. This reduces the inner search from O(n^2) to O(n), giving an overall O(n^2) solution.
Approach 1: Brute Force¶
Thought process¶
The simplest idea: check every possible triplet and track which sum is closest to the target. Using three nested loops, compute the sum for all C(n,3) triplets. Track the closest sum found.
Algorithm (step-by-step)¶
- Initialize
closest = nums[0] + nums[1] + nums[2] - Outer loop:
i = 0ton-3 - Middle loop:
j = i+1ton-2 - Inner loop:
k = j+1ton-1 - Calculate
sum = nums[i] + nums[j] + nums[k] - If
|sum - target| < |closest - target|, updateclosest = sum - Return
closest
Pseudocode¶
function threeSumClosest(nums, target):
closest = nums[0] + nums[1] + nums[2]
for i = 0 to n-3:
for j = i+1 to n-2:
for k = j+1 to n-1:
sum = nums[i] + nums[j] + nums[k]
if |sum - target| < |closest - target|:
closest = sum
return closest
Complexity¶
| Complexity | Explanation | |
|---|---|---|
| Time | O(n^3) | Three nested loops. C(n,3) = n(n-1)(n-2)/6 triplets. |
| Space | O(1) | No extra memory — only a few variables. |
Implementation¶
Go¶
// threeSumClosestBruteForce — Brute Force approach
// Time: O(n^3), Space: O(1)
func threeSumClosestBruteForce(nums []int, target int) int {
n := len(nums)
closest := nums[0] + nums[1] + nums[2]
for i := 0; i < n-2; i++ {
for j := i + 1; j < n-1; j++ {
for k := j + 1; k < n; k++ {
sum := nums[i] + nums[j] + nums[k]
if abs(sum-target) < abs(closest-target) {
closest = sum
}
}
}
}
return closest
}
Java¶
class Solution {
// threeSumClosest — Brute Force approach
// Time: O(n^3), Space: O(1)
public int threeSumClosest(int[] nums, int target) {
int n = nums.length;
int closest = nums[0] + nums[1] + nums[2];
for (int i = 0; i < n - 2; i++) {
for (int j = i + 1; j < n - 1; j++) {
for (int k = j + 1; k < n; k++) {
int sum = nums[i] + nums[j] + nums[k];
if (Math.abs(sum - target) < Math.abs(closest - target)) {
closest = sum;
}
}
}
}
return closest;
}
}
Python¶
class Solution:
def threeSumClosest(self, nums: list[int], target: int) -> int:
"""
Brute Force approach
Time: O(n^3), Space: O(1)
"""
n = len(nums)
closest = nums[0] + nums[1] + nums[2]
for i in range(n - 2):
for j in range(i + 1, n - 1):
for k in range(j + 1, n):
current_sum = nums[i] + nums[j] + nums[k]
if abs(current_sum - target) < abs(closest - target):
closest = current_sum
return closest
Dry Run¶
Input: nums = [-1, 2, 1, -4], target = 1
Initial: closest = -1 + 2 + 1 = 2
i=0 (-1):
j=1 (2):
k=2 (1): sum = -1+2+1 = 2 |2-1|=1 < |2-1|=1 → no change
k=3 (-4): sum = -1+2-4 = -3 |-3-1|=4 > 1 → no change
j=2 (1):
k=3 (-4): sum = -1+1-4 = -4 |-4-1|=5 > 1 → no change
i=1 (2):
j=2 (1):
k=3 (-4): sum = 2+1-4 = -1 |-1-1|=2 > 1 → no change
Total triplets checked: 4 (C(4,3) = 4)
Result: 2
Approach 2: Sort + Two Pointers¶
The problem with Brute Force¶
Brute Force checks all C(n,3) triplets — that's O(n^3). With n = 500, that's ~20 million operations — it might pass, but is slow. Question: "Can we reduce the search space using sorting?"
Optimization idea¶
Sort the array first. Then for each fixed element
nums[i], use two pointersleftandrightto find the best pair.Since the array is sorted: - If
sum < target, movingleftright increases the sum - Ifsum > target, movingrightleft decreases the sum - Ifsum == target, we found an exact match and return immediatelyThis way, for each
i, we scan the remaining elements in O(n) instead of O(n^2).
Algorithm (step-by-step)¶
- Sort the array
- Initialize
closest = nums[0] + nums[1] + nums[2] - For each
ifrom0ton-3: a. Skip ifnums[i] == nums[i-1](optional optimization) b. Setleft = i+1,right = n-1c. Whileleft < right:- Calculate
sum = nums[i] + nums[left] + nums[right] - If
sum == target, returntarget - If
|sum - target| < |closest - target|, updateclosest = sum - If
sum < target, moveleft++ - Else move
right--
- Calculate
- Return
closest
Pseudocode¶
function threeSumClosest(nums, target):
sort(nums)
closest = nums[0] + nums[1] + nums[2]
for i = 0 to n-3:
if i > 0 and nums[i] == nums[i-1]: continue
left = i + 1, right = n - 1
while left < right:
sum = nums[i] + nums[left] + nums[right]
if sum == target: return target
if |sum - target| < |closest - target|:
closest = sum
if sum < target: left++
else: right--
return closest
Complexity¶
| Complexity | Explanation | |
|---|---|---|
| Time | O(n^2) | Sorting is O(n log n). Outer loop O(n) * two-pointer O(n) = O(n^2). |
| Space | O(log n) | Sorting space (depends on implementation). |
Implementation¶
Go¶
// threeSumClosest — Sort + Two Pointers approach
// Time: O(n^2), Space: O(log n)
func threeSumClosest(nums []int, target int) int {
sort.Ints(nums)
n := len(nums)
closest := nums[0] + nums[1] + nums[2]
for i := 0; i < n-2; i++ {
if i > 0 && nums[i] == nums[i-1] {
continue
}
left, right := i+1, n-1
for left < right {
sum := nums[i] + nums[left] + nums[right]
if sum == target {
return target
}
if abs(sum-target) < abs(closest-target) {
closest = sum
}
if sum < target {
left++
} else {
right--
}
}
}
return closest
}
Java¶
class Solution {
// threeSumClosest — Sort + Two Pointers approach
// Time: O(n^2), Space: O(log n)
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int n = nums.length;
int closest = nums[0] + nums[1] + nums[2];
for (int i = 0; i < n - 2; i++) {
if (i > 0 && nums[i] == nums[i - 1]) continue;
int left = i + 1, right = n - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == target) return target;
if (Math.abs(sum - target) < Math.abs(closest - target)) {
closest = sum;
}
if (sum < target) {
left++;
} else {
right--;
}
}
}
return closest;
}
}
Python¶
class Solution:
def threeSumClosest(self, nums: list[int], target: int) -> int:
"""
Sort + Two Pointers approach
Time: O(n^2), Space: O(log n)
"""
nums.sort()
n = len(nums)
closest = nums[0] + nums[1] + nums[2]
for i in range(n - 2):
if i > 0 and nums[i] == nums[i - 1]:
continue
left, right = i + 1, n - 1
while left < right:
current_sum = nums[i] + nums[left] + nums[right]
if current_sum == target:
return target
if abs(current_sum - target) < abs(closest - target):
closest = current_sum
if current_sum < target:
left += 1
else:
right -= 1
return closest
Dry Run¶
Input: nums = [-1, 2, 1, -4], target = 1
Step 0: Sort → [-4, -1, 1, 2]
closest = -4 + (-1) + 1 = -4
i=0 (nums[i]=-4), left=1, right=3:
Step 1: sum = -4 + (-1) + 2 = -3 |-3-1|=4 < |-4-1|=5 → closest = -3
sum < target → left++ → left=2
Step 2: sum = -4 + 1 + 2 = -1 |-1-1|=2 < |-3-1|=4 → closest = -1
sum < target → left++ → left=3
left == right → inner loop ends
i=1 (nums[i]=-1), left=2, right=3:
Step 3: sum = -1 + 1 + 2 = 2 |2-1|=1 < |-1-1|=2 → closest = 2
sum > target → right-- → right=2
left == right → inner loop ends
i=2 → i >= n-2, outer loop ends
Total operations: 3 inner steps (vs Brute Force: 4 triplets)
Result: 2
Complexity Comparison¶
| # | Approach | Time | Space | Pros | Cons |
|---|---|---|---|---|---|
| 1 | Brute Force | O(n^3) | O(1) | Simple, no sorting needed | Slow for large inputs |
| 2 | Sort + Two Pointers | O(n^2) | O(log n) | Optimal time, early termination | Requires sorting (modifies array) |
Which solution to choose?¶
- In an interview: Approach 2 (Sort + Two Pointers) — demonstrates knowledge of sorting + two-pointer pattern
- In production: Approach 2 — optimal time complexity
- On Leetcode: Approach 2 — O(n^2) comfortably passes for n=500
- For learning: Both — Brute Force to understand the problem, Sort + Two Pointers to learn the optimization
Edge Cases¶
| # | Case | Input | Expected Output | Reason |
|---|---|---|---|---|
| 1 | Minimum input | nums=[1,1,1], target=2 | 3 | Only one triplet possible |
| 2 | Exact match | nums=[1,1,1,0], target=3 | 3 | Triplet sum equals target exactly |
| 3 | All negatives | nums=[-3,-2,-5,-1], target=-8 | -8 | Closest to -8 is -5+(-2)+(-1)=-8 |
| 4 | All zeros | nums=[0,0,0], target=1 | 0 | Sum is always 0 |
| 5 | Large target | nums=[1,2,3,4,5], target=100 | 12 | Max sum 3+4+5=12, still far from 100 |
| 6 | All same values | nums=[5,5,5,5], target=10 | 15 | Only possible sum is 15 |
| 7 | Target between two sums | nums=[-1,0,1,2], target=2 | 2 | -1+1+2=2 matches exactly |
Common Mistakes¶
Mistake 1: Forgetting to sort the array before using two pointers¶
# WRONG — two pointers on unsorted array gives incorrect results
def threeSumClosest(self, nums, target):
closest = nums[0] + nums[1] + nums[2]
for i in range(len(nums) - 2):
left, right = i + 1, len(nums) - 1
while left < right:
# Two pointers logic won't work on unsorted array!
...
# CORRECT — sort first
def threeSumClosest(self, nums, target):
nums.sort() # Essential!
...
Reason: The two-pointer technique relies on the sorted order to decide which pointer to move. Without sorting, moving left or right has no predictable effect on the sum.
Mistake 2: Using wrong distance comparison¶
# WRONG — comparing sums instead of distances
if current_sum < closest:
closest = current_sum
# CORRECT — compare absolute distances to target
if abs(current_sum - target) < abs(closest - target):
closest = current_sum
Reason: A smaller sum is not necessarily closer to the target. For example, if target=5, sum=3 (distance=2) is closer than sum=1 (distance=4), even though 1 < 3.
Mistake 3: Not returning early on exact match¶
# INEFFICIENT — continues searching even after finding exact match
if abs(current_sum - target) < abs(closest - target):
closest = current_sum
# BETTER — return immediately when exact match found
if current_sum == target:
return target
if abs(current_sum - target) < abs(closest - target):
closest = current_sum
Reason: If the sum equals the target, the distance is 0 and we cannot do better. Returning early avoids unnecessary iterations.
Related Problems¶
| # | Problem | Difficulty | Similarity |
|---|---|---|---|
| 1 | 1. Two Sum | 🟢 Easy | Finding target sum with fewer elements |
| 2 | 15. 3Sum | 🟡 Medium | Same sort + two pointers pattern, exact match |
| 3 | 18. 4Sum | 🟡 Medium | Extension to four elements |
| 4 | 167. Two Sum II | 🟡 Medium | Two pointers on sorted array |
| 5 | 259. 3Sum Smaller | 🟡 Medium | Counting triplets with sum condition |
Visual Animation¶
Interactive animation: animation.html
In the animation: - Brute Force tab — three nested loops (i, j, k) check all triplets - Sort + Two Pointers tab — fix i, move left and right pointers - Array visualization with sorting step - Distance-to-target display and best sum tracking - Custom input controls for experimenting with different arrays and targets