150NeetCode 150

12.3Sum

MediumBlind 75Two Pointers Ā· 3/5

Problem

Given an integer array nums, return all unique triplets [nums[i], nums[j], nums[k]] such that i, j, k are distinct indices and nums[i] + nums[j] + nums[k] == 0.

The result must not contain duplicate triplets (two triplets are duplicates if they hold the same values, regardless of which indices produced them). Order of triplets and of values inside a triplet does not matter.

Examples

Input:  nums = [-1, 0, 1, 2, -1, -4]
Output: [[-1, -1, 2], [-1, 0, 1]]
Explanation: (-1) + (-1) + 2 = 0 and (-1) + 0 + 1 = 0. The two -1s can form [-1, 0, 1] in two ways, but it is reported once.
Input:  nums = [0, 1, 1]
Output: []
Explanation: No triplet sums to zero.
Input:  nums = [0, 0, 0]
Output: [[0, 0, 0]]

Constraints

  • 3 <= nums.length <= 3000
  • -10^5 <= nums[i] <= 10^5

šŸ’” Key Insight

Sort first. Then fix the smallest element nums[i] and the problem reduces to Two Sum II on the sorted suffix: find nums[l] + nums[r] == -nums[i] with two pointers. Sorting also makes duplicates adjacent, so skipping equal neighbours (for i, and for l/r after a hit) removes duplicate triplets without any hash set. Total O(n²).

Brute Force

TimeO(n³)SpaceO(m)

Intuition

Try every triple of indices. To avoid duplicate value-triplets, sort the array first (so each triplet comes out in ascending order) and store results in a Set<List<Integer>>.

Algorithm

  1. Sort nums.
  2. For all i < j < k: if the sum is 0, add [nums[i], nums[j], nums[k]] to a set.
  3. Return the set as a list.

Visualization

sorted = [-4, -1, -1, 0, 1, 2]

(-1, -1, 2) at (1,2,5) → add
(-1,  0, 1) at (1,3,4) → add
(-1,  0, 1) at (2,3,4) → already in set, ignored

Code

java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums); // sorted triplets make equal value-sets identical lists
        Set<List<Integer>> found = new HashSet<>();
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                for (int k = j + 1; k < n; k++) {
                    if (nums[i] + nums[j] + nums[k] == 0) {
                        found.add(Arrays.asList(nums[i], nums[j], nums[k]));
                    }
                }
            }
        }
        return new ArrayList<>(found);
    }
}

Complexity

  • Time: O(n³) — every triple is checked.
  • Space: O(m) — m unique triplets in the set (plus sorting stack).

Complexity Comparison

Approach Time Space
Brute Force O(n³) O(m)
Hash Set per Pivot O(n²) O(n + m)
Sort + Two Pointers O(n²) O(1) extra

Common Pitfalls

  • Skipping duplicates with nums[i] == nums[i + 1] instead of nums[i] == nums[i - 1] — this skips the first -1 in [-1, -1, 2] and loses that triplet.
  • Forgetting to skip duplicate l values after a hit, producing [-2, 0, 2] twice for [-2, 0, 0, 2, 2].
  • Stopping both pointers after a hit instead of moving them — an infinite loop.
  • Breaking on nums[i] >= 0 instead of > 0 misses [0, 0, 0].