
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
i
be the first element of the triplet. - Within this loop, initiate two pointers: one (
left
) ati+1
and the other (right
) at the end of the array. This will facilitate checking pairs in a range that decreases asi
increases, avoiding recomputation and duplicates naturally. - For each position of
i
, move theleft
andright
pointers 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
left
pointer to the right to increase the sum. - If the sum is greater than zero, move the
right
pointer to the left to decrease the sum.
- If
- A significant part of avoiding duplicates involves, after finding a valid triplet, skipping all other
i
values which are the same asnums[i]
. This is done by incrementingi
as 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
set
namedresultSet
to store the unique triplets and anunordered_set
namedduplicateSet
to track duplicates in the array. - Utilize an
unordered_map
namedindexMap
to store the indices of elements for quick access and checking. - Iterate through each element in
nums
using a loop indexed byi
. TheduplicateSet
helps 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
indexMap
to 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
resultSet
to 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
Set
namedresult
to store triplet lists without duplicates. Two additional collections are employed:duplicates
to 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
duplicates
set.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 thisneeded
element has previously appeared at the correct position (right after the first element of the triplet) using theprevious
map.Store and Return Results: If a valid triplet is found, it is sorted to ensure order consistency, then added to the
result
set. 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
MapItem
used for creating a hash map, but in this particular implementation, Hash handles are defined but not utilized. - Define a function
sort_compare
for comparison, which is used by the quicksort function to order the array elements. - The function
findThreeSum
begins by sorting the input array usingqsort
. - The function initializes variables for dynamic memory allocation to store the result triplets and their sizes (
triplets
andcolSizes
). - 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 (
left
andright
) identifies potential triplets. These pointers adjust based on the sum comparison to zero:- If the sum is less than zero, the
left
pointer is incremented. - If the sum is more than zero, the
right
pointer is decremented. - If the sum is zero, a suitable triplet is found and stored in the dynamically allocated
triplets
array. 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 reflecting
the 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,
triples
andprocessed
, 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
processed
set 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
found
to 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
triples
set 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
result
to store unique triplets and another set calledduplicates
to track numbers already processed to avoid duplicate triplets. - An
observed
dictionary 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
value1
only if it hasn't been processed before (checked using theduplicates
set). - The inner loop then tests possible combinations with
value1
by looking for a third numbercomp
(computed as the negative sum ofvalue1
andvalue2
) that has been mapped to the current index inobserved
. - If a valid
comp
is found within the observed dictionary at the correct index, it confirms a unique triplet which is then added to theresult
set.
- 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.
No comments yet.