Skip to content

Commit c95ac53

Browse files
committed
docs(algorithms, two-pointers): three sum documentation
1 parent 8c30b66 commit c95ac53

23 files changed

+104
-36
lines changed

algorithms/intervals/insert_interval/README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,27 @@ Return the updated list of intervals.
2525

2626
## Solution
2727

28-
We first want to create a new list merged to store the merged intervals we will return at the end.
28+
We first want to create a new list `merged` to store the merged intervals we will return at the end.
2929

3030
This solution operates in 3 phases:
31-
1. Add all the intervals ending before newInterval starts to merged.
32-
2. Merge all overlapping intervals with newInterval and add that merged interval to merged.
33-
3. Add all the intervals starting after newInterval to merged.
31+
1. Add all the intervals ending before `newInterval` starts to `merged`.
32+
2. Merge all overlapping intervals with `newInterval` and add that merged interval to `merged`.
33+
3. Add all the intervals starting after `newInterval` to `merged`.
3434

3535
### Phase 1
3636

37-
In this phase, we add all the intervals that end before newInterval starts to merged. This involves iterating through the
38-
intervals list until the current interval no longer ends before newInterval starts (i.e. intervals[i][1] >= newInterval[0]).
37+
In this phase, we add all the intervals that end before `newInterval` starts to `merged`. This involves iterating through the
38+
`intervals` list until the current interval no longer ends before `newInterval` starts (i.e. `intervals[i][1] >= newInterval[0]`).
3939

4040
![Solution 1](./images/solutions/insert_interval_solution_1.png)
4141
![Solution 2](./images/solutions/insert_interval_solution_2.png)
4242

4343
### Phase 2
4444

4545
In this phase, we merge all the intervals that overlap with newInterval together into a single interval by updating
46-
newInterval to be the minimum start and maximum end of all the overlapping intervals. This involves iterating through
47-
the intervals list until the current interval starts after newInterval ends (i.e. intervals[i][0] > newInterval[1]).
48-
When that condition is met, we add newInterval to merged and move onto phase 3.
46+
`newInterval` to be the minimum start and maximum end of all the overlapping intervals. This involves iterating through
47+
the intervals list until the current interval starts after `newInterval` ends (i.e. `intervals[i][0] > newInterval[1]`).
48+
When that condition is met, we add `newInterval` to merged and move onto phase 3.
4949

5050
![Solution 3](./images/solutions/insert_interval_solution_3.png)
5151
![Solution 4](./images/solutions/insert_interval_solution_4.png)

algorithms/two_pointers/three_sum/README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,61 @@ Input: nums = [0,0,0]
3232
Output: [[0,0,0]]
3333
Explanation: The only possible triplet sums up to 0.
3434
```
35+
36+
## Solution
37+
38+
We can leverage the two-pointer technique to solve this problem by first sorting the array. We can then iterate through
39+
each element in the array. The problem then reduces to finding two numbers in the rest of the array that sum to the
40+
negative of the current element, which follows the same logic as the Two Sum (Sorted Array) problem.
41+
42+
![Solution 1](./images/solutions/three_sum_solution_1.png)
43+
44+
Since our first triplet sums to 0, we can add it to our result set.
45+
46+
![Solution 2](./images/solutions/three_sum_solution_2.png)
47+
![Solution 3](./images/solutions/three_sum_solution_3.png)
48+
![Solution 4](./images/solutions/three_sum_solution_4.png)
49+
![Solution 5](./images/solutions/three_sum_solution_5.png)
50+
![Solution 6](./images/solutions/three_sum_solution_6.png)
51+
52+
### Avoiding Duplicates
53+
54+
As soon as we find a triplet that sums to 0, we can add it to our result set. We then have to move our left and right
55+
pointers to look for the next triplet while avoiding duplicate triplets. We can do this by moving the left and right
56+
pointers until they point to different numbers than the ones they were pointing to before.
57+
Here we move the left pointer once until it reaches the last -1 in the array. Then, we can move both the left and right
58+
pointers so that they both point to new numbers.
59+
60+
![Solution 7](./images/solutions/three_sum_solution_7.png)
61+
![Solution 8](./images/solutions/three_sum_solution_8.png)
62+
63+
Here we can do another iteration of the Two Sum problem using the new positions of the left and right pointers.
64+
65+
![Solution 9](./images/solutions/three_sum_solution_9.png)
66+
![Solution 10](./images/solutions/three_sum_solution_10.png)
67+
![Solution 11](./images/solutions/three_sum_solution_11.png)
68+
69+
At this point our left and right pointers have crossed, so we can move our iterator to the next number in the array.
70+
71+
### Avoiding Duplicates II
72+
73+
In this case, since the next number in the array is the same as the previous number, we can skip it. We can do this by
74+
moving our iterator until it points to a new number.
75+
76+
![Solution 12](./images/solutions/three_sum_solution_12.png)
77+
![Solution 13](./images/solutions/three_sum_solution_13.png)
78+
![Solution 14](./images/solutions/three_sum_solution_14.png)
79+
80+
And we're ready to start the Two Sum algorithm again, so we reset our left and right pointers, and start the algorithm.
81+
82+
![Solution 15](./images/solutions/three_sum_solution_15.png)
83+
![Solution 16](./images/solutions/three_sum_solution_16.png)
84+
![Solution 17](./images/solutions/three_sum_solution_17.png)
85+
86+
### Termination
87+
88+
Our algorithm terminates when i reaches the 3rd to last element in the array (i.e., i < n - 2). This is because we need
89+
at least 2 more elements after i for left and right to form a triplet.
90+
91+
![Solution 18](./images/solutions/three_sum_solution_18.png)
92+
![Solution 19](./images/solutions/three_sum_solution_19.png)

algorithms/two_pointers/three_sum/__init__.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,48 @@
44
def three_sum(nums: List[int]) -> List[List[int]]:
55
"""
66
Complexity Analysis:
7+
Ww assume that n is the length of the input array
78
8-
Time Complexity: O(nlog(n)) + O(n^2) = O(n^2) the O(nlog(n)) is due to sorting
9-
Space Complexity: O(1) as no extra space is taken up
9+
Time Complexity: O(nlog(n)) + O(n^2) = O(n^2) the O(nlog(n)) is due to sorting, overall, the time complexity is O(n²).
10+
This is due to the nested loops in the algorithm. We perform n iterations of the outer loop, and each iteration
11+
takes O(n) time to use the two-pointer technique.
12+
13+
Space Complexity: O(n²) as no extra space is taken up. We need to store all distinct triplets that sum to 0, which
14+
can be at most O(n²) triplets.
1015
1116
Args:
1217
nums (list): input list of integers
1318
Return:
1419
list: list of lists of integers
1520
"""
1621
result = []
17-
# Time Complexity: O(nlog(n))
22+
# Time Complexity: O(nlog(n)) sorting in place. This may incur space complexity of O(n) due to Python's timesort
23+
# using temporary storage to handle the in place sorting
1824
nums.sort()
1925

2026
for idx, num in enumerate(nums):
27+
# Increment to avoid duplicates
2128
if idx > 0 and num == nums[idx - 1]:
2229
continue
2330

2431
left, right = idx + 1, len(nums) - 1
2532

2633
while left < right:
27-
sum_ = num + nums[left] + nums[right]
28-
if sum_ > 0:
34+
total = num + nums[left] + nums[right]
35+
if total > 0:
2936
right -= 1
30-
elif sum_ < 0:
37+
elif total < 0:
3138
left += 1
3239
else:
40+
# add the triplet
3341
result.append([num, nums[left], nums[right]])
34-
left += 1
35-
while nums[left] == nums[left - 1] and left < right:
42+
43+
# move the left pointer to avoid duplicates while it is still less than the right
44+
while left < right and nums[left] == nums[left + 1]:
3645
left += 1
46+
while left < right and nums[right] == nums[right - 1]:
47+
right -= 1
48+
left += 1
49+
right -= 1
50+
3751
return result
38.2 KB
Loading
38.7 KB
Loading
37.8 KB
Loading
33.1 KB
Loading
38.3 KB
Loading
37.5 KB
Loading
34.7 KB
Loading

0 commit comments

Comments
 (0)