Current code
Before discussing the algorithm I want to discuss the current code.
The code currently uses functional approaches - like forEach()
methods. This is great for readability but because a function is called for every iteration of each loop, performance can be worse than a regular for
loop - e.g. each function adds to the call stack.
The current code also uses hasOwnProperty
. For a plain object the in
operator could be used since it doesn't matter if the property would be inherited or not.
The last block is this:
const finalErr = []
Object.keys(triplet_memory).forEach(el => {
const elements = el.split('/').map((element) => {
return parseInt(element)
})
finalErr.push(elements)
})
return finalErr
It is interesting that there is a .map()
call nested inside a .forEach()
loop that pushes elements into an array - the latter is the essence of a .map()
call. So the .forEach()
could be simplified to a .map()
call:
return Object.keys(triplet_memory).map(el => {
return el.split('/').map((element) => {
return parseInt(element)
})
})
This way there is no need to manually create finalErr
, push elements into it and then return it at the end.
Different Algorithm
There are multiple posts about this problem on code review (and SO as well). One review of a c++ implementation by Emily L. suggests an algorithm with \$O(n^2)\$ time complexity.
Better algorithm
We can easily reach O(n^2)
time complexity.
We need to find all a
, b
, c
such that a+b+c=0
. Note that this is equivalent to c = -(a+b)
. Hence if we can check if c
exists in the input in O(1)
time, then we just need to try each pair of a
and b
and see if a matching c
exists. Since there are O(n^2)
pairs we have O(n^2*1)
time.
A hash set provides the necessary O(1)
check if c
is present in the input.
(I'm not going to handle the three zeros, you can figure that out).
Pseudocode:
unordered_map<int> hashset;
for(auto& x : input){ hashset.put(x); }
for(int i = 0; i < input.size(); ++i){
for(int j = i+1; j < input.size(); j++){
auto c = -(input[i] + input[j]);
if(hashset.contains(c)){
output.addTuple(input[i], input[j], - c);
}
}
}
A similar approach could be taken - with JS an object like num_occurrence
could be used for the hashset, but it wouldn't need to count the number of occurrences. Alternatively a Set could be used with the .has()
method for checking if an element exists in the set.