10 - 3Sum
Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] where nums[i] + nums[j] + nums[k] == 0, and the indices i, j and k are all distinct.
The output should not contain any duplicate triplets. You may return the output and the triplets in any order.
Examples¶
Example 1
Input:
Output:
Example 2
Input:
Output:
Example 3
Input:
Output:
Solution¶
Java Code¶
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
// Step 1: Sort the array to use two-pointer approach and easily handle duplicates
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
for (int i = 0; i < nums.length - 2; i++) {
// Step 2: Skip duplicate elements for the first position
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
// Step 3: Use two pointers for the remaining part of the array
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
// Triple found!
res.add(Arrays.asList(nums[i], nums[left], nums[right]));
// Step 4: Skip duplicate elements for left and right pointers
while (left < right && nums[left] == nums[left + 1]) {
left++;
}
while (left < right && nums[right] == nums[right - 1]) {
right--;
}
left++;
right--;
} else if (sum < 0) {
left++;
} else {
right--;
}
}
}
return res;
}
}
Java Collections Framework Components Used¶
1. List & ArrayList¶
What they are¶
List is an interface representing an ordered collection, and ArrayList is its resizable-array implementation.
How they are used¶
Used to store the resulting triplets.ArrayList is chosen for its efficient \(O(1)\) amortized addition.
2. Arrays.sort()¶
What it is¶
A utility method in the java.util.Arrays class used to sort arrays of primitives or objects. For primitives, it uses a Dual-Pivot Quicksort.
Why it is used¶
Sorting is crucial for:
1. Handling Duplicates: By sorting, identical elements are adjacent, making them easy to skip.
2. Two-Pointer Logic: Allows us to move pointers systematically (left++ to increase sum, right-- to decrease it).
3. Arrays.asList()¶
What it is¶
A factory method that returns a fixed-size list backed by the specified array.
How it is used¶
Provides a clean and concise way to create the inner triplet lists.Intuition¶
The problem asks for triplets summing to zero without duplicates. A brute-force \(O(n^3)\) approach would be too slow.
- Sort the array: This allows us to use the two-pointer technique for a \(O(n^2)\) solution.
- Fix the first element: Iterate through the array, treating
nums[i]as the first member of a potential triplet. - Pointers for the rest: For each
i, setleft = i + 1andright = length - 1. - Avoid Duplicates:
- Skip
nums[i]if it's the same as the previous element. - After finding a valid sum, skip duplicates for
leftandrightbefore moving them again.
Complexity Analysis¶
Time Complexity¶
Sorting takes \(O(n \log n)\). The main loop runs \(O(n)\) times, and inside it, the two-pointer traversal takes \(O(n)\), resulting in \(O(n^2)\).
Space Complexity¶
Depends on the implementation of Arrays.sort(). Dual-Pivot Quicksort typically uses \(O(\log n)\) space for the recursion stack. (Excluding the output list).
Key Takeaways¶
- Sort first to simplify duplicate handling and enable two-pointer optimization.
- Skipping adjacent duplicates is the key to uniqueness in the results.
- JCF utilities like
Arrays.sortandArrays.asListdrastically reduce boilerplate code.