Skip to content

Commit 72c1e92

Browse files
authored
Merge pull request #74 from AbdulWahab938/feature/3-sum
Solution #15 - Abdul Wahab - 16/07/2025
2 parents 28cd73b + 57fd780 commit 72c1e92

File tree

4 files changed

+187
-0
lines changed

4 files changed

+187
-0
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# 15. 3Sum
2+
3+
**Difficulty:** Medium
4+
**Category:** Arrays, Two Pointers, Hashing
5+
**Leetcode Link:** [Problem Link](https://leetcode.com/problems/3sum)
6+
7+
---
8+
9+
## 📝 Introduction
10+
11+
Given an integer array `nums`, return all the unique triplets `[nums[i], nums[j], nums[k]]` such that:
12+
- `i != j`, `i != k`, and `j != k`,
13+
- `nums[i] + nums[j] + nums[k] == 0`
14+
15+
The solution must not contain duplicate triplets.
16+
17+
---
18+
19+
## 💡 Approach & Key Insights
20+
21+
The main idea is to find all unique triplets in the array that sum to zero. Since the problem demands uniqueness and excludes repeated indices, care must be taken in how the triplets are collected. We can go from a brute force solution using three nested loops to a highly optimized two-pointer strategy that leverages sorting and duplicate skipping.
22+
23+
---
24+
25+
## 🛠️ Breakdown of Approaches
26+
27+
### 1️⃣ Brute Force / Naive Approach
28+
29+
- **Explanation:**
30+
Iterate through all combinations of three distinct indices using three nested loops. For each combination, check if the sum is zero. Use a set to store sorted triplets to avoid duplicates.
31+
32+
- **Time Complexity:** O(N³ * log M)
33+
Where `N` is the length of the array and `M` is the number of unique triplets (for insertion into the set).
34+
35+
- **Space Complexity:** O(M)
36+
For storing unique triplets in a set.
37+
38+
- **Example/Dry Run:**
39+
40+
Input: `[-1, 0, 1, 2, -1, -4]`
41+
Valid triplets (after sorting): `[-1, -1, 2]`, `[-1, 0, 1]`
42+
Output: `[[-1, -1, 2], [-1, 0, 1]]`
43+
44+
---
45+
46+
### 2️⃣ Better Approach (Using HashSet)
47+
48+
- **Explanation:**
49+
Fix two elements using nested loops and calculate the third element required to make the sum zero. Use a HashSet to check if this third element has already been seen. Ensure only elements between the second loop's index range are included in the HashSet to prevent using the same element multiple times.
50+
51+
- **Time Complexity:** O(N² * log M)
52+
Due to two loops and set insertions.
53+
54+
- **Space Complexity:** O(M + N)
55+
For storing unique triplets and temporary HashSet.
56+
57+
- **Example/Dry Run:**
58+
59+
Input: `[-1, 0, 1, 2, -1, -4]`
60+
Valid triplets: `[-1, -1, 2]`, `[-1, 0, 1]`
61+
Output: `[[-1, -1, 2], [-1, 0, 1]]`
62+
63+
---
64+
65+
### 3️⃣ Best / Final Optimized Approach (Two Pointers + Sorting)
66+
67+
- **Explanation:**
68+
Sort the array first. Use one fixed pointer `i`, and two moving pointers `j` and `k` (`j = i+1`, `k = n-1`). Move the pointers inward while skipping duplicates. If the sum is zero, store the triplet. If the sum is too small, increment `j`; if too large, decrement `k`.
69+
70+
- **Time Complexity:** O(N²)
71+
Due to one fixed pointer and a linear scan with two pointers.
72+
73+
- **Space Complexity:** O(M)
74+
Only for storing the result triplets.
75+
76+
- **Example/Dry Run:**
77+
78+
Sorted Input: `[-4, -1, -1, 0, 1, 2]`
79+
i = 0 → j = 1, k = 5 → `-4 + (-1) + 2 = -3` → j++
80+
...
81+
Found: `[-1, -1, 2]` and `[-1, 0, 1]`
82+
83+
---
84+
85+
## 📊 Complexity Analysis
86+
87+
| Approach | Time Complexity | Space Complexity |
88+
| ---------------- | ----------------------- | ---------------------- |
89+
| Brute Force | O(N³ * log M) | O(M) |
90+
| Better Approach | O(N² * log M) | O(M + N) |
91+
| Best Approach | O(N²) | O(M) |
92+
93+
---
94+
95+
## 📉 Optimization Ideas
96+
97+
- Sorting the array simplifies duplicate management.
98+
- Using two pointers eliminates the need for a HashSet and reduces time complexity.
99+
- Skipping duplicates on the fly avoids unnecessary checks and result post-processing.
100+
101+
---
102+
103+
## 📌 Example Walkthroughs & Dry Runs
104+
105+
plaintext
106+
Example:
107+
Input: [-1, 0, 1, 2, -1, -4]
108+
Sorted: [-4, -1, -1, 0, 1, 2]
109+
110+
Iteration:
111+
i = 0 → arr[i] = -4, j = 1, k = 5
112+
Sum = -4 + (-1) + 2 = -3 → j++
113+
114+
i = 1 → arr[i] = -1, j = 2, k = 5
115+
Sum = -1 + (-1) + 2 = 0 → Store triplet [-1, -1, 2], j++, k--
116+
117+
i = 1, j = 3, k = 4
118+
Sum = -1 + 0 + 1 = 0 → Store triplet [-1, 0, 1], j++, k--
119+
120+
Duplicates skipped using while loops
121+
122+
Output: [[-1, -1, 2], [-1, 0, 1]]
123+
124+
---
125+
126+
## 🔗 Additional Resources
127+
128+
- [GeeksForGeeks Explanation](https://www.geeksforgeeks.org/find-triplets-array-whose-sum-equal-zero/)
129+
130+
---
131+
132+
Author: Abdul Wahab
133+
Date: 19/07/2025
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
class Solution {
2+
public:
3+
vector<vector<int>> threeSum(vector<int>& nums) {
4+
vector<vector<int>> ans;
5+
int n = nums.size();
6+
sort(nums.begin(), nums.end());
7+
for (int i = 0; i < n; i++) {
8+
// Skip duplicates for first element
9+
if (i != 0 && nums[i] == nums[i - 1]) continue;
10+
int j = i + 1, k = n - 1;
11+
while (j < k) {
12+
int sum = nums[i] + nums[j] + nums[k];
13+
if (sum < 0) {
14+
j++;
15+
} else if (sum > 0) {
16+
k--;
17+
} else {
18+
ans.push_back({nums[i], nums[j], nums[k]});
19+
j++;
20+
k--;
21+
// Skip duplicates for second element
22+
while (j < k && nums[j] == nums[j - 1]) j++;
23+
// Skip duplicates for third element
24+
while (j < k && nums[k] == nums[k + 1]) k--;
25+
}
26+
}
27+
}
28+
return ans;
29+
}
30+
};
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
class Solution:
2+
def threeSum(self, nums: List[int]) -> List[List[int]]:
3+
nums.sort()
4+
n = len(nums)
5+
ans = []
6+
for i in range(n):
7+
if i != 0 and nums[i] == nums[i - 1]:
8+
continue
9+
j, k = i + 1, n - 1
10+
while j < k:
11+
s = nums[i] + nums[j] + nums[k]
12+
if s < 0:
13+
j += 1
14+
elif s > 0:
15+
k -= 1
16+
else:
17+
ans.append([nums[i], nums[j], nums[k]])
18+
j += 1
19+
k -= 1
20+
while j < k and nums[j] == nums[j - 1]:
21+
j += 1
22+
while j < k and nums[k] == nums[k + 1]:
23+
k -= 1
24+
return ans

0 commit comments

Comments
 (0)