|
| 1 | +# 15 - 3 Sum |
| 2 | + |
| 3 | +Difficulty: medium |
| 4 | +Done: No |
| 5 | +Last edited: February 22, 2022 1:23 AM |
| 6 | +Topic: array, sorting, two pointers |
| 7 | + |
| 8 | +## Problem |
| 9 | + |
| 10 | +Given an integer array nums, return all the triplets `[nums[i], nums[j], nums[k]]` such that `i != j`, `i != k`, and `j != k`, and `nums[i] + nums[j] + nums[k] == 0`. |
| 11 | + |
| 12 | +Notice that the solution set must not contain duplicate triplets. |
| 13 | + |
| 14 | +## Solution |
| 15 | + |
| 16 | +Problem is framed like the popular two sum where we find 2 values $(x, y)$ which add up to given target, which can be solved by finding if difference between target and value $(target - x)$ exists in array. |
| 17 | + |
| 18 | +However, here we are required to work with 3 values $(x, y, z)$ and **find all triplets where sum of values is zero** $x+y+z=0$. This must be done without repeating the elements, though input array can contain duplicates. |
| 19 | + |
| 20 | +This approach will only work with sorted array |
| 21 | + |
| 22 | +### Pseudo |
| 23 | + |
| 24 | +1. Sort array |
| 25 | +2. Iterate through elements, setting current element as the pivot $x$. |
| 26 | + 1. if current value (lowest) is greater than zero, then this would indicate there are only non-negative elements, which cannot sum to 0. |
| 27 | + 2. if current value is same as preceding (duplicate), then skip. |
| 28 | + 3. Proceed to step 3 |
| 29 | +3. Use two pointer approach to compare values, starting with *left_ptr* at position $x+1$, and *right_ptr* at the end of the array or $len(nums)$-1. We want to find all pairs whose sum is equal to 0, or $(x+y+z)=0$. |
| 30 | + |
| 31 | + We will do so by creating separate function which essentially performs two-sum. Loop while *left_ptr* is smaller than *right_ptr* |
| 32 | + |
| 33 | + 1. If $sum(x, y, z)$ is greater than 0, we will increment *left_ptr* |
| 34 | + 2. Elif $sum(x,y, z)$ is less than 0, we will decrement *right_pt* |
| 35 | + 3. if sum is zero, meaning **triplet found,** add to results list. Increment left and decrement right. Increment left while while $left = left+1$, to skip duplicates. |
| 36 | + |
| 37 | +## Whiteboard |
| 38 | + |
| 39 | +[http://excalidraw.com](http://excalidraw.com) |
| 40 | + |
| 41 | +## Code |
| 42 | + |
| 43 | +```python |
| 44 | +class Solution: |
| 45 | + def threeSum(self, nums: List[int]) -> List[List[int]]: |
| 46 | + triplets = [] |
| 47 | + nums.sort() |
| 48 | + |
| 49 | + for i in range(len(nums)): |
| 50 | + # check if all elements are non-negative |
| 51 | + if nums[i] > 0: |
| 52 | + break |
| 53 | + |
| 54 | + # skip duplicates |
| 55 | + # call two_sum function to find triplets with i as target |
| 56 | + if nums[i-1] != nums[i] or i == 0: |
| 57 | + self.two_sum(i, nums, triplets) |
| 58 | + |
| 59 | + return triplets |
| 60 | + |
| 61 | + |
| 62 | + def two_sum(self, i: int, nums: List[int], triplets: List[List[int]]): |
| 63 | + # define left & right pointers |
| 64 | + # loop while left & right pointers aren't at same position l < r |
| 65 | + |
| 66 | + left = i + 1 |
| 67 | + right = len(nums) - 1 |
| 68 | + |
| 69 | + while left < right: |
| 70 | + total = nums[i] + nums[left] + nums[right] |
| 71 | + |
| 72 | + |
| 73 | + #if sum > 0, increment left |
| 74 | + if total < 0: |
| 75 | + left += 1 |
| 76 | + |
| 77 | + # if sum < 0, decrement right |
| 78 | + elif total > 0: |
| 79 | + right -= 1 |
| 80 | + |
| 81 | + else: |
| 82 | + # if sum is 0, add to triplets list |
| 83 | + triplets.append([nums[i], nums[left], nums[right]]) |
| 84 | + left += 1 |
| 85 | + right -= 1 |
| 86 | + |
| 87 | + while left < right and nums[left] == nums[left-1]: |
| 88 | + # skip duplicates |
| 89 | + left += 1 |
| 90 | +``` |
0 commit comments