Presort and Two Pointer Solution
/*
Time Complexity - O(n^2)
Space Complexity - O(n^2) from possible number of triplets + some space from js native sort
Overview:
- Sort the array
- Iterate through elements calling threeSum(i) on -ve and unique elements
- threeSum has two pointers low and high with start, direction: i+1 --> <-- end
- So until low and high don't meet, move pointers & check values at i, low, high adding to result if sum is 0
*/
function findZeroSum(arr) {
const triplets = [],
len = arr.length,
end = arr.length - 1
arr = arr.sort((a, b) => a - b)
threeSum(0) // [1]
for (let i = 1; i < len; i++) {
if (arr[i] > 0) break // [2]
if (arr[i - 1] !== arr[i]) threeSum(i)
}
function threeSum(i) {
let low = i + 1,
high = end
while (low < high) {
const sum = arr[i] + arr[low] + arr[high]
// [3]
if (sum < 0 || (low > i + 1 && arr[low] === arr[low - 1])) low++
else if (sum > 0 || (high < end && arr[high] === arr[high + 1])) high--
else triplets.push([arr[i], arr[low++], arr[high--]])
}
}
return triplets
}
/*
Notes:
[1] call for i = 0 once outside and start i = 1, so it doesn't need to be checked in every iteration
[2] threeSum function pointers go from i+1 --> <-- end. So +ve nums will be already be checked in previous iterations.
Also you can't get three sum with +ve nums only
[3] threeSum comparisons:
- if sum is < 0 or low val is duplicate, low pointer needs to be bigger. Eg for sum, -8 + 2 + 1 = -5
- else if sum is > 0 or high val is duplicate, higher pointer needs to be smaller. Eg for sum, -1 + (-2) + 8 = 5
- else sum is 0 so push triplet to triplets
------------------------------------------------------------------------------------------------------------------
*/
// Tests
console.log(findZeroSum([-1, 0, 1, 2, -1, -4]))
console.log(findZeroSum([-1, 0, 1]))
Hash Map Solution
/*
--------------------------------------------------------------------------------------------
Slightly optimized version using hashmap (sets). Doesn't check already checked first values.
Runs much slower than two pointer solution. Like 3 times as slow. Da fuq. y doe?
Time Complexity - O(n^2)
Space Complexity - O(n^2) from the 'seen' set. Same as possible number of triplets.
*/
function findZeroSumHash(arr) {
const triplets = [],
len = arr.length,
found = new Set(),
duplicateVals = new Set()
for (let i = 0; i < len; i++) {
const seen = new Set(),
first = arr[i]
if (duplicateVals.has(first)) continue
duplicateVals.add(first)
for (let j = i + 1; j < len; j++) {
const second = arr[j],
third = -first - second
if (seen.has(third)) {
const min = Math.min(first, second, third),
max = Math.max(first, second, third),
stringPair = `${min},${max}`
if (!found.has(stringPair)) {
found.add(stringPair)
triplets.push([first, second, third].join(','))
}
}
seen.add(second)
}
}
return triplets
}