Title: Find Four Elements that Sum to a Target
In this guide, you’ll learn how to solve the classic 4Sum problem: given an array of integers and a target value, find every unique combination of four elements whose sum equals the target. This is a direct extension of the two-sum and three-sum problems, and it shows up often in interviews that test whether you can generalize a two-pointer technique.
We’ll walk through a sorting-and-two-pointers approach that runs in O(n^3) time, trace it step by step on a small array, and cover the duplicate-handling details that trip up most candidates.
Understanding the Problem
Given an integer array numbers and an integer target, you need to return all unique quadruplets [a, b, c, d] from numbers such that a + b + c + d equals target. The same index cannot be used twice inside one quadruplet, but the same value can appear more than once if the array contains duplicates.
The order of values inside a quadruplet and the order of quadruplets in the result do not matter, as long as no duplicate combination appears twice in the output.
A brute-force solution checks every combination of four indices, which costs O(n^4) and becomes impractical quickly. Sorting the array first lets you fix two numbers and scan the rest with two pointers, cutting the work down to O(n^3).
Approach
- Handle the trivial case: if
numbers.lengthis less than 4, return an empty result immediately. - Sort
numbersin ascending order so duplicates sit next to each other and two-pointer scanning becomes valid. - Iterate
ifrom 0 ton - 4, skipping it whenevernumbers[i] == numbers[i - 1]to avoid repeating the first element of a quadruplet. - For each
i, iteratejfromi + 1ton - 3, skipping it whenevernumbers[j] == numbers[j - 1](andjis not immediately afteri) to avoid repeating the second element. - Set
left = j + 1andright = n - 1, then move the two pointers toward each other based on hownumbers[i] + numbers[j] + numbers[left] + numbers[right]compares totarget. - When the sum equals
target, record the quadruplet, then advanceleftandrightpast any duplicate values before continuing. - When the sum is less than
target, incrementleft; when it is greater, decrementright. - Repeat until
leftandrightmeet, then move on to the nextj, and eventually the nexti.
Java Program
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class FourSum {
public static List<List<Integer>> findQuadruplets(int[] numbers, int target) {
List<List<Integer>> result = new ArrayList<>();
int n = numbers.length;
if (n < 4) {
return result;
}
Arrays.sort(numbers);
for (int i = 0; i < n - 3; i++) {
if (i > 0 && numbers[i] == numbers[i - 1]) {
continue;
}
for (int j = i + 1; j < n - 2; j++) {
if (j > i + 1 && numbers[j] == numbers[j - 1]) {
continue;
}
int left = j + 1;
int right = n - 1;
while (left < right) {
long sum = (long) numbers[i] + numbers[j] + numbers[left] + numbers[right];
if (sum == target) {
result.add(Arrays.asList(numbers[i], numbers[j], numbers[left], numbers[right]));
while (left < right && numbers[left] == numbers[left + 1]) {
left++;
}
while (left < right && numbers[right] == numbers[right - 1]) {
right--;
}
left++;
right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
}
return result;
}
public static void main(String[] args) {
int[] numbers = {1, 0, -1, 0, -2, 2};
int target = 0;
List<List<Integer>> quadruplets = findQuadruplets(numbers, target);
System.out.println(quadruplets);
}
}Explanation of the Program
findQuadrupletsfirst checks for arrays shorter than four elements and returns an empty list rather than risk an out-of-bounds pointer.Arrays.sort(numbers)puts the array in ascending order so duplicate values become adjacent and the two-pointer scan is valid.- The outer loop variable
iand the inner loop variablejfix the first two elements of each candidate quadruplet. - The duplicate-skip checks on
numbers[i]andnumbers[j]prevent the same leading pair from being processed more than once. leftandrightscan inward from just afterjto the end of the array, and the sum is cast tolongbefore comparison to avoid integer overflow.- When a match is found, both pointers skip past any following duplicates before the search continues, which keeps the result free of repeated quadruplets.
Step-by-Step Trace
Consider the sorted array [-3, -1, 0, 2, 4, 5] with target = 2, where i = 0 (numbers[i] = -3) and j = 1 (numbers[j] = -1) are already fixed. The table below traces the inner while loop as left and right scan the remaining sub-array [0, 2, 4, 5]:
| Iteration | numbers[left] | numbers[right] | sum | sum vs target | action |
|---|---|---|---|---|---|
| 1 | 0 | 5 | 1 | less than | left++ |
| 2 | 2 | 5 | 3 | greater than | right– |
| 3 | 2 | 4 | 2 | equal | record [-3, -1, 2, 4], then left++, right– |
At the end of each iteration, the window between left and right has shrunk by at least one position, so every pair of positions in the sorted sub-array is tested at most once before the loop ends.
Examples
Example 1: Multiple Quadruplets with Negative Numbers
This is the input most people associate with the 4Sum problem. Negative and positive values combine in more than one way to reach the target.
int[] numbers = {1, 0, -1, 0, -2, 2};
int target = 0;
// findQuadruplets(numbers, target) returns:
// [[-2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]]Example 2: No Quadruplet Reaches the Target
When every possible combination falls short of the target, the method should return an empty list rather than null or throw an exception.
int[] numbers = {1, 2, 3, 4};
int target = 100;
// findQuadruplets(numbers, target) returns:
// []Example 3: Repeated Values Still Produce One Quadruplet
When the same value appears five times, only one quadruplet should be reported even though several index combinations would otherwise sum to the target.
int[] numbers = {2, 2, 2, 2, 2};
int target = 8;
// findQuadruplets(numbers, target) returns:
// [[2, 2, 2, 2]]Common Mistakes to Avoid
The two-pointer approach depends on several details that are easy to get wrong under interview pressure.
- Forgetting to sort first – the duplicate-skip checks and the left/right pointer narrowing both assume ascending order; without
Arrays.sort(numbers), valid quadruplets get missed or duplicated. Always sort before the nested loops begin. - Comparing against the wrong neighbor when skipping duplicates – checking
numbers[i] == numbers[i + 1]instead ofnumbers[i] == numbers[i - 1]skips the first occurrence of a value entirely. Compare each index to the one before it. - Letting the four-way sum overflow – adding four
intvalues nearInteger.MAX_VALUEsilently wraps around and produces a false match or a missed one. Cast the running sum tolongbefore comparing it totarget. - Advancing only one pointer after a match – moving just
leftor justrightafter recording a quadruplet re-adds the same combination on the next iteration. Advance both pointers past duplicates and then one step further.
Edge Cases to Test
Walking through these cases out loud is exactly what an interviewer wants to see before you start coding.
- Array with fewer than four elements
- Empty array
- All elements identical
- Multiple quadruplets sharing the same values
- Target unreachable by any combination
- Negative numbers mixed with positive numbers
- Sum of four values near Integer.MAX_VALUE or Integer.MIN_VALUE
- Null array reference
Additional Considerations
The sorting step costs O(n log n), and the nested i, j loops combined with the inner two-pointer scan cost O(n^3), so the overall time complexity is O(n^3). This is a significant improvement over the O(n^4) brute-force search over every combination of four indices.
Space complexity is O(1) beyond the output list if you ignore the space used by Arrays.sort, though the result itself can hold up to O(n^2) quadruplets in the worst case where many duplicate values exist.
Arrays.sort(numbers) mutates the input array in place. If the caller needs to preserve the original order, sort a clone with numbers.clone() instead of sorting the parameter directly.
The Integer.MIN_VALUE / Integer.MAX_VALUE edge case matters specifically because four large values summed as plain int can overflow before the comparison runs, which is why the program casts the running sum to long.
Interview Follow-up Questions
Once you have the base solution working, expect the interviewer to push on these variations.
- What if you must return the quadruplets without changing the original array’s order? – sort a cloned copy of the array instead of sorting
numbersin place, and look up original positions separately if indices are needed. - What if you need k numbers summing to a target instead of exactly four? – generalize the recursion: reduce a kSum problem to a (k – 1)Sum problem on a smaller sub-array, bottoming out at the two-pointer two-sum case.
- What if you need to answer many different target queries against the same array? – sort once upfront, then consider precomputing all pairwise sums into a hash map keyed by sum so each query can look up complementary pairs in roughly O(n^2) instead of re-deriving them.
- What if the numbers arrive as a continuous stream too large to fit in memory? – two-pointer scanning needs random access to a sorted structure, so true streaming 4Sum is impractical at scale; the realistic answer is to discuss why, and to propose maintaining a bounded sorted window or external sort as a partial mitigation.
Conclusion
The 4Sum problem rewards the same pattern you’d use for two-sum and three-sum: sort first, then shrink the search space with pointers instead of brute-forcing every combination. The trickiest part is not the arithmetic, it’s handling duplicates correctly at every level of nesting.
Try adapting findQuadruplets to return the quadruplets’ original indices, or to generalize it into a kSum method, to confirm you understand why each duplicate-skip check is positioned where it is. You can learn more about array-based problems like this one in our Arrays category.



