
Problem Statement
In the given problem, we need to identify all unique triplets within an integer array nums that can sum up to zero. The triplets must be formed such that no index is used more than once within a single triplet, meaning for a triplet [nums[i], nums[j], nums[k]], it must hold that i != j, i != k, and j != k. Additionally, it's crucial to ensure that the resulting list of triplets does not include any duplicates. This scenario requires an efficient approach to both generate potential triplets and to check if their sum equals zero, while also maintaining uniqueness amongst the results in terms of the values and not just the indices.
Examples
Example 1
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]. Notice that the order of the output and the order of the triplets does not matter.
Example 2
Input:
nums = [0,1,1]
Output:
[]
Explanation:
The only possible triplet does not sum up to 0.
Example 3
Input:
nums = [0,0,0]
Output:
[[0,0,0]]
Explanation:
The only possible triplet sums up to 0.
Constraints
3 <= nums.length <= 3000-105 <= nums[i] <= 105
Approach and Intuition
The solution to this problem revolves around avoiding unnecessary computations and ensuring that we do not revisit the same elements in such a way that would produce duplicate triplets. Here's a step-by-step breakdown:
- First, sort the array. This will make it easier to skip duplicates and use the two-pointer technique efficiently.
- Iterate through the sorted array using a loop. Let the current element at index
ibe the first element of the triplet. - Within this loop, initiate two pointers: one (
left) ati+1and the other (right) at the end of the array. This will facilitate checking pairs in a range that decreases asiincreases, avoiding recomputation and duplicates naturally. - For each position of
i, move theleftandrightpointers based on the sum:- If
nums[i] + nums[left] + nums[right] == 0, record the triplet and shift both pointers to skip any duplicates around them. - If the sum is less than zero, move the
leftpointer to the right to increase the sum. - If the sum is greater than zero, move the
rightpointer to the left to decrease the sum.
- If
- A significant part of avoiding duplicates involves, after finding a valid triplet, skipping all other
ivalues which are the same asnums[i]. This is done by incrementingias long asnums[i]is the same as the number at the next index.
This method ensures that each potential triplet is checked minimally and efficiently, leveraging sorting and the two-pointer technique, which are particularly powerful for such array transformation problems given their ability to significantly cut down the number of required operations. Moreover, the array being sorted helps prevent the formation of duplicate triplets and allows for easy skipping of repeated values, which optimizes the overall process.
Solutions
- C++
- Java
- C
- JavaScript
- Python
class Solution {
public:
vector<vector<int>> findThreeSum(vector<int>& nums) {
set<vector<int>> resultSet;
unordered_set<int> duplicateSet;
unordered_map<int, int> indexMap;
for (int i = 0; i < nums.size(); ++i)
if (duplicateSet.insert(nums[i]).second) {
for (int j = i + 1; j < nums.size(); ++j) {
int needed = -nums[i] - nums[j];
auto it = indexMap.find(needed);
if (it != indexMap.end() && it->second == i) {
vector<int> triple = {nums[i], nums[j], needed};
sort(triple.begin(), triple.end());
resultSet.insert(triple);
}
indexMap[nums[j]] = i;
}
}
return vector<vector<int>>(resultSet.begin(), resultSet.end());
}
};
The provided solution in C++ addresses the problem of finding all unique triplets in an array whose sum equals zero. This program defines a class named Solution with a method findThreeSum that accepts an integer vector nums and returns a vector of integer vectors.
- Start by creating a
setnamedresultSetto store the unique triplets and anunordered_setnamedduplicateSetto track duplicates in the array. - Utilize an
unordered_mapnamedindexMapto store the indices of elements for quick access and checking. - Iterate through each element in
numsusing a loop indexed byi. TheduplicateSethelps ensure that each number is processed only once as the main element of the triplet. - For each unique number, use a nested loop indexed by
j, starting fromi + 1, to try finding the two other numbers that form a valid triplet. - Calculate the third required number as
needed = -nums[i] - nums[j]to make the sum zero. - Use
indexMapto find if the third number has been seen before, and check whether it was associated with the current indexi. - If the conditions are met, meaning the triplet sums to zero, normalize the triplet by sorting and then add it to
resultSet. - After all pairs are processed, convert
resultSetto a vector before returning to ensure no duplicates.
This technique efficiently reduces potential duplicates using sets and makes use of hashing for quick access and checking, leading to an organized and concise solution for the "3Sum" problem.
class Solution {
public List<List<Integer>> findTriplets(int[] numbers) {
Set<List<Integer>> result = new HashSet<>();
Set<Integer> duplicates = new HashSet<>();
Map<Integer, Integer> previous = new HashMap<>();
for (int i = 0; i < numbers.length; ++i) if (duplicates.add(numbers[i])) {
for (int j = i + 1; j < numbers.length; ++j) {
int needed = -numbers[i] - numbers[j];
if (previous.containsKey(needed) && previous.get(needed) == i) {
List<Integer> triplet = Arrays.asList(numbers[i], numbers[j], needed);
Collections.sort(triplet);
result.add(triplet);
}
previous.put(numbers[j], i);
}
}
return new ArrayList<>(result);
}
}
The provided Java solution is structured to resolve the "3Sum" problem, where the goal is to identify all unique triplets in an array that sum up to zero. Here's how this implementation functions effectively:
Initialize Collections: Utilizes a
Setnamedresultto store triplet lists without duplicates. Two additional collections are employed:duplicatesto track any repeated elements and avoid re-evaluation, andprevious, aMap, to associate each number with its index for reference.Iterate with Conditions: Runs a loop through the array, using a nested loop to find pairs that could form a viable triplet with the current element. This only proceeds if the current element hasn't been evaluated before, ensuring this by checking its presence in the
duplicatesset.Calculate and Find Needed Values: Inside the nested loop, calculates the required third element (named
needed) that would make the sum of the triplet zero. Checks if thisneededelement has previously appeared at the correct position (right after the first element of the triplet) using thepreviousmap.Store and Return Results: If a valid triplet is found, it is sorted to ensure order consistency, then added to the
resultset. This prevents duplicate triplets of different orders. Finally, the stored triplets are returned as a new list.
This solution is efficient with its use of data structures to manage checks and storage, and ensures that the output is a list of unique triplets that meet the required sum condition, skillfully combining iterative checks with hash-based data structures for effective search and storage operations.
typedef struct {
int key;
int value;
UT_hash_handle hash_handle;
} MapItem;
int sort_compare(const void* p1, const void* p2) { return *(int*)p1 - *(int*)p2; }
int** findThreeSum(int* elements, int size, int* count,
int** colSizes) {
MapItem* hashmap = NULL;
qsort(elements, size, sizeof(int), sort_compare);
int** triplets = (int**)malloc(size * size * sizeof(int*));
*count = 0;
*colSizes = (int*)malloc(size * size * sizeof(int));
for (int i = 0; i < size - 2; ++i) {
if (i > 0 && elements[i] == elements[i - 1]) continue;
int left = i + 1, right = size - 1;
MapItem* current;
while (left < right) {
int currentSum = elements[i] + elements[left] + elements[right];
if (currentSum < 0) {
++left;
} else if (currentSum > 0) {
--right;
} else {
int* currentTriplet = (int*)malloc(3 * sizeof(int));
currentTriplet[0] = elements[i];
currentTriplet[1] = elements[left];
currentTriplet[2] = elements[right];
triplets[*count] = currentTriplet;
(*colSizes)[*count] = 3;
++(*count);
while (left < right && elements[left] == elements[left + 1]) ++left;
while (left < right && elements[right] == elements[right - 1]) --right;
++left;
--right;
}
}
}
return triplets;
}
The provided C code implements a solution for finding all unique triplets in an array that sum up to zero. This is commonly known as the "3Sum" problem.
Follow these steps in the code:
- Define a structure
MapItemused for creating a hash map, but in this particular implementation, Hash handles are defined but not utilized. - Define a function
sort_comparefor comparison, which is used by the quicksort function to order the array elements. - The function
findThreeSumbegins by sorting the input array usingqsort. - The function initializes variables for dynamic memory allocation to store the result triplets and their sizes (
tripletsandcolSizes). - A for-loop iterates through the array, ensuring no duplicate triplets are added by skipping equal consecutive elements.
- Within the for-loop, a while-loop with two pointers (
leftandright) identifies potential triplets. These pointers adjust based on the sum comparison to zero:- If the sum is less than zero, the
leftpointer is incremented. - If the sum is more than zero, the
rightpointer is decremented. - If the sum is zero, a suitable triplet is found and stored in the dynamically allocated
tripletsarray. Then both pointers are moved to skip any duplicate elements immediately succeeding them.
- If the sum is less than zero, the
- Finally, the function returns the array
triplets, containing all found triplets, andcolSizes reflectingthe size of each triplet sub-array.
The resulting function efficiently locates all triplets that sum to zero by incorporating sorting and a two-pointer technique to reduce the complexity compared to brute-force solutions.
var threeSumUnique = function (arr) {
const triples = new Set();
const processed = new Set();
const found = new Map();
for (let p = 0; p < arr.length; ++p)
if (!processed.has(arr[p])) {
processed.add(arr[p]);
for (let q = p + 1; q < arr.length; ++q) {
let comp = -arr[p] - arr[q];
if (found.has(comp) && found.get(comp) === p) {
let triplet = [arr[p], arr[q], comp].sort((x, y) => x - y);
triples.add(JSON.stringify(triplet));
}
found.set(arr[q], p);
}
}
return Array.from(triples, el => JSON.parse(el));
};
The JavaScript solution implements a threeSumUnique function that identifies all unique triplets in an array which sum up to zero. The function employs a combination of data structures to efficiently track and search for necessary components to form these triples. Here is an overview of how the function effectively manages complexity and ensures uniqueness in its results:
- Initializes two collections,
triplesandprocessed, and a Map calledfound. - Uses
triples, a Set data structure, to store the resulting triplets in a way that automatically avoids duplicates since sets in JavaScript do not allow repeated values. - Iterates through each element in the array using a for-loop. For each element not already processed, adds it to the
processedset to prevent reconsideration in subsequent iterations of the loop. - A nested loop then looks for two other elements that complete the triplet so their sum equals zero. The completion is calculated using the negative sum of the current and the inner loop elements.
- Uses the Map
foundto track whether the complement of the current and inner elements was identified in the exact same outer loop cycle. - If an appropriate triplet is found, it is added to
triplesset after converting it to a string to ensure uniqueness and sorted order. - Finally, converts the JSON string values back into arrays for the output.
This method offers an efficient way to solve the problem while handling the triplet uniqueness requirement effectively by using the combination of Set and Map structures and taking advantage of JSON for temporarily storing complex objects. Ensure your input array is well-formed and consists of integers to correctly utilize this function.
class Solution:
def threeSum_unique(self, numbers: List[int]) -> List[List[int]]:
result, duplicates = set(), set()
observed = {}
for index, value1 in enumerate(numbers):
if value1 not in duplicates:
duplicates.add(value1)
for k, value2 in enumerate(numbers[index + 1:]):
comp = -value1 - value2
if comp in observed and observed[comp] == index:
result.add(tuple(sorted((value1, value2, comp))))
observed[value2] = index
return [list(t) for t in result]
The provided Python3 solution targets the problem of finding all unique triplets in an array of integers that sum up to zero. The approach involves:
- Using a set called
resultto store unique triplets and another set calledduplicatesto track numbers already processed to avoid duplicate triplets. - An
observeddictionary maps each number to its index, ensuring that components of the triplet are identified correctly without revisiting elements. - Iterate over the numbers array with two nested loops:
- The outer loop selects an element
value1only if it hasn't been processed before (checked using theduplicatesset). - The inner loop then tests possible combinations with
value1by looking for a third numbercomp(computed as the negative sum ofvalue1andvalue2) that has been mapped to the current index inobserved. - If a valid
compis found within the observed dictionary at the correct index, it confirms a unique triplet which is then added to theresultset.
- The outer loop selects an element
The key points in this solution include:
- Use of set data structures to ensure all triplets are unique and to handle the inherent uniqueness requirement efficiently.
- Efficient handling of indices and values using dictionaries to minimize unnecessary calculations and lookups.
Finally, the list of triplets stored as tuples in the result set is converted back to a list of lists before returning, complying with the expected output format. This method efficiently minimizes redundant processing and avoids overcounting while allowing for an intuitive triplet-building logic using hash maps.