Data Structures & Algorithms (Two Pointers): Three Sum

January 13, 2026

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.

NOTE: The solution set must not contain duplicate triplets. The order of the output and the order of the triplets does not matter.

Example

Input: nums = [-1,0,1,2,-1,-4]
Output: [[-1,-1,2],[-1,0,1]]
Explanation:
- nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0.
- nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0.
- nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0.

The distinct triplets are [-1,0,1] and [-1,-1,2].

Solve Here: Leetcode 15


Design Rationale

The following are the key concepts to consider when designing an efficient algorithm for this problem:

Q. How to make sure no triplets with the same set of numbers are added to the result?

A simple approach is to sort the array. Once sorted, identical triplets will have the same ordered representation. For example:

Before sorting: nums = [-1,0,1,2,-1,-4]
After sorting: nums = [-4,-1,-1,0,1,2]

- nums[1] + nums[3] + nums[4] = (-1) + 0 + 1 = 0
- nums[2] + nums[3] + nums[4] = (-1) + 0 + 1 = 0  <- duplicate triplet


Approach 1: Sorting + Nested Loops

Use three nested loops to iterate through all possible triplets and keep track of the unique ones whose sum is 0.

Algorithm

1. Sort the input array.
Initialize an empty set to store the unique triplets.
3. Iterate through the array using three pointers i, j, and k:
    - For each triplet, check if nums[i] + nums[j] + nums[k] == 0:
        - If the sum is equal to 0, store the triplet to the result set.
4. Convert the result set into list and return it.
Note

During traversal, skip a value if it is the same as the value processed in the previous iteration. Processing the same value again can only reproduce triplets we've already considered. Skipping it avoids duplicate work and duplicate results.

Implementation

public List<List<Integer>> threeSum(int[] nums) {
    // 1. Sort the input array
    Arrays.sort(nums);

    // 2. Iterate over the sorted set of triplets
    Set<List<Integer>> resultSet = new HashSet<>();
    for(int i = 0; i < nums.length - 2; i++) {

        // Optimization: Skip duplicates
        if (i > 0 && nums[i] == nums[i - 1]) continue;

        for(int j = i + 1; j < nums.length - 1; j++) {

            // Optimization: Skip duplicates
            if (j > i + 1 && nums[j] == nums[j - 1]) continue;

            for(int k = j + 1; k < nums.length; k++) {

                // Optimization: Skip duplicates
                if (k > j + 1 && nums[k] == nums[k - 1]) continue;

                if (nums[i] + nums[j] + nums[k] == 0) {
                    List<Integer> triplet = List.of(nums[i], nums[j], nums[k]);
                    resultSet.add(triplet);
                }
            }
        }
    }
    
    return new ArrayList<>(resultSet);
}

Time Complexity

Sorting the array takes O(n log n) time. The nested loops take O(n^3) time. Hence, the overall time complexity is O(n^3).

Space Complexity

There are n(n-1)(n-2)/6 ~ O() possible combinations of three elements, but the sum = 0 constraint greatly limits how many of those combinations can actually be valid.

Once we choose two numbers a and b, the third number is completely determined: c = (a+b). So we don't have O(n) choices for the third element anymore. That's the key reason the number of valid unique triplets is bounded by O(n²).

So the overall space complexity is O().


Approach 2: Sorting + Two Pointers

For every element i, we can use two pointers j and k to find the other two elements such that nums[j] + nums[k] + nums[i] == 0.

Algorithm

1. Sort the input array.
2. Iterate through the array using a pointer i:
    - For each element i, let j = i + 1 and k = nums.length - 1:
        - while j < k:
            - if nums[i] + nums[j] + nums[k] == 0:
                - store the triplet to the result set.
            - else if nums[i] + nums[j] + nums[k] < 0:
                - increment j.
            - else:
                - decrement k.
3. Convert the result set into list and return it.

Implementation

public List<List<Integer>> threeSum(int[] nums) {
    // 1. Sort the input array
    Arrays.sort(nums);

    // 2. Iterate over each element i in the sorted array
    Set<List<Integer>> resultSet = new HashSet<>();
    for(int i = 0; i < nums.length - 2; i++) {
        // Optimization: Skip duplicates
        if (i > 0 && nums[i] == nums[i - 1]) continue;

        int j = i + 1;
        int k = nums.length - 1;
        while (j < k) {
            if (nums[i] + nums[j] + nums[k] == 0) {
                resultSet.add(List.of(nums[i], nums[j], nums[k]));
                j++;
                k--;
            } else if (nums[i] + nums[j] + nums[k] < 0) {
                j++;
            } else {
                k--;
            }
        }
    }

    return new ArrayList<>(resultSet);
}

Time Complexity

Sorting the array takes O(n log n) time. The nested loop perform a linear search through the remaining elements for each i, resulting in O() time. Hence, the overall time complexity is O(n log n) + O() = O().

Space Complexity

There are O() possible combinations of two elements. Hence, the overall space complexity is O().