4

There was this problem that asked to return all unique triplets of elements of an array which add up to zero (swapping two elements' places in the triplet does not count as unique).

I came up with the following code:

function threeSum(nums) {
  nums.sort((a, b) => a - b);
  const result = [];
  for (let i = 0; i < nums.length; i++) {
    // skipping duplicates
    if (i !== 0 && nums[i] === nums[i - 1]) continue;
    let left = i + 1;
    let right = nums.length - 1;
    while (left < right) {
      const s = nums[i] + nums[left] + nums[right];
      // too small; move to the right
      if (s < 0) left++;
      // too big; move to the left
      else if (s > 0) right--;
      // bingo
      else {
        result.push([nums[i], nums[left], nums[right]]);
        //skipping duplicates
        while (left + 1 < right && nums[left] === nums[left + 1]) left++;
        while (right - 1 > left && nums[right] === nums[right - 1]) right--;
        left++;
        right--;
      }
    }
  }
  return result;
};
// expected output: [[-4,-2,6],[-4,0,4],[-4,1,3],[-4,2,2],[-2,-2,4],[-2,0,2]]
console.log(threeSum([-4,-2,-2,-2,0,1,2,2,2,3,3,4,4,6,6]))

I think the time complexity is O(n^2). There is a sort at the beginning that we assume is O(n log n) and the nested loop works approximately (n^2)/2 times which translates to O(n^2). So, at the end, we are left with O(n log n + n^2) and since n log n is of lesser degree it is removed, leaving us with O(n^2).

I'm not quite sure about the space complexity, but intuitively I guess that's an O(n).

Can you please, correct/confirm my reasoning/guess about the time- and space complexity?

user1984
  • 5,990
  • 2
  • 13
  • 32

3 Answers3

7

This looks like the standard approach to solving 3SUM in quadratic time. However, I disagree with the other answers concerning space complexity and believe it is quadratic as there can be quadratically many distinct triples summing to 0.


Consider the following example:

[1, -1, 2, -2, ..., n-1, 1-n, n, -n], where n is even.

In this particular case, there are n²/4 - n/2 distinct triplets summing to 0 (see derivation of this result below). That's quadratically many in the size of the array (the array being 2*n elements long). Because you store all these solutions, that means you need a quadratic amount of memory, and a linear O(n) won't cut it.

Thus, worst case space complexity is also quadratic (it is easy to show that there can not be more than quadratically many distinct triplets summing to 0).


Derivation of the result :

For any positive number a in this sequence, we can pick b = k and c = -(a+k) to get a triplet where a is the smallest element in absolute value, provided that k > a and a+k <= n i.e. a < k <= n-a. That gives us n-2*a choices for k (we never count any twice as b is always positive and c always negative).

Summing over all possible a's, we get a total of : sum((n-2*a) for a in 1...n/2) = n²/4 - n/2 = Ω(n²).

Tassle
  • 563
  • 3
  • 9
  • thanks @tassle that's enlightening. I see where you're headed. Just made a small test where the length of result was over two times of the length of the input. But your answer is a little bit cryptic :) can you come up with a concrete example? Thank you for your help. – user1984 Aug 24 '19 at 20:36
  • The gist of it is, for the particular example I consider (that is, [1,-1,2,-2,...,n,-n] for any even n you want), there are `n²/4 - n/2` distinct triplets summing to 0. That's quadratically many in the size of the array (the array being 2*n elements long). Because you store all these solutions, that means you need a quadratic amount of memory, and a linear O(n) won't cut it. – Tassle Aug 24 '19 at 20:47
  • As for concreteness, I don't know how I can get any more concrete than the example I gave :/ – Tassle Aug 24 '19 at 20:48
  • nah, that's fine :) thank you. May be add the example to your answer for some future ghosts who are lost. – user1984 Aug 24 '19 at 20:50
  • Better like that? :) – Tassle Aug 24 '19 at 20:59
  • @Tassle future ghost here. I might have made a silly error. But in the example - `[1, -1, 2, -2, 3, -3, 4, -4]`, the answer is 4 unique pairs. But the formula `n^2/4 - n/2` gives us `4^2/4 - n/2 = 2 unique pairs` – Devansh Sharma Nov 05 '22 at 21:21
1

I agree on your thoughts about time complexity. You have a loop in the loop and you always move a pointer in the inner loop by at least 1 (left or right). So it is, like you said, O(n^2 / 2) or O(n^2)

EDIT: For space complexity I agree with Tassle's answer

Dimitri L.
  • 4,499
  • 1
  • 15
  • 19
0

Yes, time complexity is O(n^2) where n = nums.length and your explanation for the same itself is sufficient.

Coming on the space complexity O(n) is also correct because of the merge sort algorithm used in the sort() method which has this space complexity. Space complexity refers to the extra elements/variables space that you are writing in your code apart from the given problem specific variables. For the code apart from the sort() method, there are two variables 'left' and 'right' along with an array result so this loop has space complexity of O(n+2), and then corresponding to them in internal while loop is also having a variable 's', then please observe that in every iteration there are 2 possibilities:-

  1. it's the same container(i.e. memory location) whose contents(i.e. variable's value) gets changed and thus overall it's only 3 containers which have been used which concludes the Space complexity as O(constant) or simply O(1)
  2. Every time different container is allocated to the variable for it's contents; however, this will be always accompanied by clearing the hold on previous container. Thus, overall we have only 3 extra containers at a time which will again lead to space complexity as O(1).

Now overall space complexity of the program would be O(n)+O(n+2)+O(1) which results in final solution of O(n).

Hope it helps!

Sharad Nanda
  • 406
  • 1
  • 15
  • 27
  • 1
    That is helpful, thank you. But, we also have the `result` array where we keep track of all the solution triplets. That's additional space. The question is: what is the upper bound/maximum number of possible solutions that could potentially be added to the `result` array? – user1984 Aug 24 '19 at 20:27
  • Sincere apologies, I missed that. I have rectified my answer. – Sharad Nanda Aug 24 '19 at 20:37