LeetCode #16 — Medium

3Sum Closest

A complete visual walkthrough of the sort + two pointer approach — tracking the closest sum to a target instead of an exact match.

Solve on LeetCode
The Problem

Problem Statement

Given an integer array nums of length n and an integer target, find three integers at distinct indices in nums such that the sum is closest to target.

Return the sum of the three integers.

You may assume that each input would have exactly one solution.

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).

Constraints:

  • 3 <= nums.length <= 500
  • -1000 <= nums[i] <= 1000
  • -104 <= target <= 104
Patterns Used

Roadmap

  1. Brute Force — Check All Triplets
  2. The Core Insight — Sort + Two Pointers
  3. Algorithm Walkthrough
  4. Edge Cases
  5. Full Annotated Code
  6. Interactive Demo
  7. Complexity Analysis
Step 01

Brute Force — Check All Triplets

The most straightforward approach: try every combination of three elements, compute the sum, and keep track of whichever sum is closest to the target.

Naive O(n³) Approach

int closest = nums[0] + nums[1] + nums[2];
for (int i = 0; i < n; i++)
    for (int j = i + 1; j < n; 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;
        }

For n = 1000, this checks roughly ~167 million triplets. It works, but is far too slow for LeetCode constraints.

Why it fails

O(n³)
Time complexity
TLE
Too slow for n up to 1000
💡

Can we do better? Yes. This problem is a variant of 3Sum. Instead of finding sums equal to zero, we track the sum closest to a target. The same sort + two pointer technique applies, reducing us from O(n³) to O(n²).

Step 02

The Core Insight — Sort + Two Pointers

Sort the array first. Then for each fixed element nums[i], use two pointers to scan the remaining elements. Instead of checking sum == 0, compare |sum - target| against the current best and keep the closer one.

The Strategy

1
Sort the array
Enables the two-pointer technique. Sorted order tells us which direction to move.
2
Initialize closest with the first triplet
Set closest = nums[0] + nums[1] + nums[2] as a starting reference.
3
Fix one element, two pointers converge
i iterates from 0. left starts at i+1, right at the end.
4
Compare and move
If |sum - target| is smaller than the current best, update closest. If sum < target, move left up. If sum > target, move right down. If sum == target, return immediately.

Why does sorting make this work? In a sorted array, the sum of a triplet is monotonically affected by pointer movement. Moving the left pointer right increases the sum; moving the right pointer left decreases it. This means we can always steer toward the target without backtracking.

Step 03

Algorithm Walkthrough

Let's trace through the example nums = [-1, 2, 1, -4], target = 1. After sorting:

Sorted Array

-4
-1
1
2

Initial closest = nums[0] + nums[1] + nums[2] = -4 + (-1) + 1 = -4. Difference from target: |(-4) - 1| = 5.

Iteration: i = 0, fix nums[0] = -4

-4fix
-1L
1
2R
sum = -4 + (-1) + 2 = -3 |(-3) - 1| = 4 < |(-4) - 1| = 5 New best! closest = -3
sum (-3) < target (1), so move L right.
-4fix
-1
1L
2R
sum = -4 + 1 + 2 = -1 |(-1) - 1| = 2 < |(-3) - 1| = 4 New best! closest = -1
sum (-1) < target (1), move L right. But L would cross R, so this fixed element is done.

Iteration: i = 1, fix nums[1] = -1

-1fix
1L
2R
sum = -1 + 1 + 2 = 2 |2 - 1| = 1 < |(-1) - 1| = 2 New best! closest = 2
sum (2) > target (1), move R left. But R would cross L, so done.

Final Result

closest = 2
(-1) + 1 + 2 = 2, just 1 away from target
🎯

Notice the progression: closest went from -4 (diff 5) to -3 (diff 4) to -1 (diff 2) to 2 (diff 1). Each time we found a better sum, we updated. The two-pointer technique systematically narrows in on the target from both sides.

Step 04

Edge Cases

Make sure your solution handles these correctly:

Exactly 3 Elements
[1, 1, 1], target = 2
Output: 3. Only one possible triplet. The outer loop runs once, inner loop immediately terminates.
Sum Equals Target
[0, 1, 2], target = 3
Output: 3. When sum == target, return immediately. The difference is zero, so nothing can be closer.
All Negative
[-5, -3, -1], target = 5
Output: -9. The closest possible sum is the largest three elements: -5 + (-3) + (-1) = -9.
All Positive
[1, 2, 3, 4], target = 2
Output: 6. Smallest possible sum is 1 + 2 + 3 = 6, which is the closest we can get to 2.
💡

No duplicate handling needed! Unlike 3Sum, we do not need to skip duplicates because we are returning a single integer (the closest sum), not a list of unique triplets. Duplicates in the array won't produce wrong answers — at worst they cause redundant comparisons.

Step 05

Full Annotated Code

class Solution {
    public int threeSumClosest(int[] nums, int target) {

        // Step 1: Sort — enables two-pointer technique
        Arrays.sort(nums);

        // Initialize with the first triplet's sum
        int closest = nums[0] + nums[1] + nums[2];

        for (int i = 0; i < nums.length - 2; i++) {

            int left = i + 1, right = nums.length - 1;

            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];

                // Update closest if this sum is nearer to target
                if (Math.abs(sum - target) < Math.abs(closest - target)) {
                    closest = sum;
                }

                if (sum < target) {
                    left++;    // Need a larger sum → move left right
                } else if (sum > target) {
                    right--;   // Need a smaller sum → move right left
                } else {
                    return sum; // Exact match — can't do better
                }
            }
        }
        return closest;
    }
}
Step 06

Interactive Demo

Enter an array and a target, then step through the algorithm to see how the two pointers converge on the closest sum.

⚙ 3Sum Closest Visualizer



Step 07

Complexity Analysis

Time
O(n2)
Space
O(log n)

Sorting costs O(n log n), then the outer loop runs O(n) times with an inner two-pointer scan of O(n) each, giving O(n2) total. Space is O(1) — we only use a few integer variables and the sort is in-place.

Approach Breakdown

BRUTE FORCE
O(n3) time
O(1) space

Three nested loops enumerate every triplet (i, j, k), computing the sum and comparing its distance to the target. This examines n*(n-1)*(n-2)/6 combinations, giving O(n3). Only a single variable tracks the closest sum, so space is O(1).

OPTIMAL
O(n2) time
O(1) space

After an O(n log n) sort, the outer loop fixes one element in O(n). For each fixed element, two pointers converge from both ends in O(n), steering toward the target based on whether the current sum is too low or too high. Total: O(n2). Only pointer variables are used, so space stays O(1).

🎯

Identical complexity to 3Sum. Tracking the "closest" sum instead of an "exact" match does not change the time or space. The two-pointer movement logic is the same — sum < target moves left up, sum > target moves right down — we simply compare distances instead of checking equality.

Coach Notes

Common Mistakes

Review these before coding to avoid predictable interview regressions.

Moving both pointers on every comparison

Wrong move: Advancing both pointers shrinks the search space too aggressively and skips candidates.

Usually fails on: A valid pair can be skipped when only one side should move.

Fix: Move exactly one pointer per decision branch based on invariant.