3Sum Leetcode | Leetcode 15 Solution

The 3Sum problem is a popular coding challenge on LeetCode that tests your ability to implement efficient algorithms for finding combinations. This blog will walk you through various approaches, from the brute force method to optimized solutions, with complete explanations, time complexities, and Java implementations.

Problem Statement

3Sum: Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that:

  • i, j, and k are distinct indices,
  • nums[i] + nums[j] + nums[k] == 0, and
  • Triplets should not contain duplicate sets.

You can return the answer in any order.

Approach 1: Brute Force (Naive Solution)

The most straightforward way to solve this problem is to use three nested loops to check all possible combinations of triplets. While this solution is simple to implement, it is highly inefficient.

Algorithm

  1. Use three loops to iterate over all triplets.
  2. Check if the sum of the triplet equals 0.
  3. Store the triplet in the result set to avoid duplicates.

Java Code

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

public class ThreeSumBruteForce {
    public static List<List<Integer>> threeSum(int[] nums) {
        Set<List<Integer>> result = new HashSet<>();
        int n = nums.length;

        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++) {
                    if (nums[i] + nums[j] + nums[k] == 0) {
                        List<Integer> triplet = List.of(nums[i], nums[j], nums[k]);
                        triplet.sort(Integer::compareTo); // Sort to avoid duplicate sets
                        result.add(triplet);
                    }
                }
            }
        }

        return new ArrayList<>(result);
    }
}

Time Complexity

  • Time: O(n3)O(n^3)O(n3), as we use three nested loops.
  • Space: O(k)O(k)O(k), where kkk is the number of unique triplets.

Approach 2: Sorting + Two Pointers

This approach is much more efficient and uses sorting combined with the two-pointer technique to reduce the complexity.

Algorithm

  1. Sort the array to enable efficient duplicate handling and use of two pointers.
  2. Fix the first element of the triplet (nums[i]).
  3. Use two pointers (left and right) to find the remaining two elements.
  4. Adjust pointers based on the sum.

Java Code

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

public class ThreeSumTwoPointers {
    public static List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums); // Sort the array

        for (int i = 0; i < nums.length - 2; i++) {
            if (i > 0 && nums[i] == nums[i - 1]) continue; // Skip duplicates for the first number
            
            int left = i + 1, right = nums.length - 1;
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                
                if (sum == 0) {
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    while (left < right && nums[left] == nums[left + 1]) left++; // Skip duplicates for left
                    while (left < right && nums[right] == nums[right - 1]) right--; // Skip duplicates for right
                    left++;
                    right--;
                } else if (sum < 0) {
                    left++;
                } else {
                    right--;
                }
            }
        }

        return result;
    }
}

Time Complexity

  • Time: O(n2)O(n^2)O(n2), as we use sorting (O(nlog⁡n)O(n \log n)O(nlogn)) and a two-pointer loop.
  • Space: O(k)O(k)O(k), where kkk is the number of unique triplets stored in the result.

Approach 3: Hashing-Based Solution

Instead of using two pointers, we can leverage a hash set to store complements during the inner loop.

Algorithm

  1. Fix the first element of the triplet (nums[i]).
  2. Use a hash set to track elements in the inner loop.
  3. Check if the complement of the current number exists in the hash set.

Java Code

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

public class ThreeSumHashing {
    public static List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums); // Sort to handle duplicates easily
        List<List<Integer>> result = new ArrayList<>();

        for (int i = 0; i < nums.length - 2; i++) {
            if (i > 0 && nums[i] == nums[i - 1]) continue; // Skip duplicates for the first number
            
            HashSet<Integer> seen = new HashSet<>();
            for (int j = i + 1; j < nums.length; j++) {
                int complement = -nums[i] - nums[j];
                if (seen.contains(complement)) {
                    result.add(Arrays.asList(nums[i], nums[j], complement));
                    while (j + 1 < nums.length && nums[j] == nums[j + 1]) j++; // Skip duplicates
                }
                seen.add(nums[j]);
            }
        }

        return result;
    }
}

Time Complexity

  • Time: O(n2)O(n^2)O(n2), as we iterate through the array and perform hash set operations.
  • Space: O(n)O(n)O(n), for the hash set.

Conclusion

The two-pointer approach is the most efficient and widely used solution for the 3Sum problem. It strikes a balance between simplicity and performance, making it ideal for competitive programming and interviews. The hashing solution is a good alternative but requires extra space.

Try implementing these solutions and see which one works best for your needs!

Leave a comment