|
| 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 |
0 commit comments