Skip to content

Commit 28cd73b

Browse files
authored
Merge pull request #75 from AbdulWahab938/feature/4-sum
Solution #18 - Abdul Wahab - 16/07/2025
2 parents 4d88bdb + 2356691 commit 28cd73b

File tree

4 files changed

+226
-0
lines changed

4 files changed

+226
-0
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# 18. 4Sum
2+
3+
**Difficulty:** Medium
4+
**Category:** Arrays, Two Pointers, Hashing
5+
**Leetcode Link:** [4Sum Problem](https://leetcode.com/problems/4sum/)
6+
7+
---
8+
9+
## 📝 Introduction
10+
11+
Given an array `nums` of `n` integers and an integer `target`, return all unique quadruplets `[nums[a], nums[b], nums[c], nums[d]]` such that:
12+
13+
- `0 <= a, b, c, d < n`
14+
- `a`, `b`, `c`, and `d` are distinct
15+
- `nums[a] + nums[b] + nums[c] + nums[d] == target`
16+
17+
The result must not contain duplicate quadruplets.
18+
19+
---
20+
21+
## 💡 Approach & Key Insights
22+
23+
To solve this problem, we explore different strategies from brute-force to optimal:
24+
25+
- Start by checking every combination of four numbers (brute force).
26+
- Reduce the number of loops by leveraging hashing for lookups (better approach).
27+
- Use sorting and two pointers to achieve an optimal time complexity (final approach).
28+
- Remove duplicates using sorted input and pointer movement logic.
29+
30+
---
31+
32+
## 🛠️ Breakdown of Approaches
33+
34+
### 1️⃣ Brute Force / Naive Approach
35+
36+
- **Explanation:**
37+
- Use four nested loops to pick all combinations of four distinct indices.
38+
- For each quadruplet, if their sum equals the target, sort it and insert it into a set (to avoid duplicates).
39+
- Finally, return all unique sorted quadruplets.
40+
41+
- **Time Complexity:** O(N⁴ * log M)
42+
- 4 loops + set insertions (log M where M is number of unique quads)
43+
44+
- **Space Complexity:** O(M)
45+
- To store unique quadruplets in a set.
46+
47+
- **Example/Dry Run:**
48+
49+
Example input: `[1, 0, -1, 0, -2, 2]`, Target = 0
50+
Process:
51+
Check every 4-tuple → Add valid ones to set
52+
Output: `[[-2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]]`
53+
54+
---
55+
56+
### 2️⃣ Optimized Approach (Using 3 Loops + HashSet)
57+
58+
- **Explanation:**
59+
- Use three nested loops (`i`, `j`, `k`) to select three numbers.
60+
- Calculate the required fourth number as `target - (nums[i] + nums[j] + nums[k])`.
61+
- Search for this number in a temporary HashSet (built on-the-fly).
62+
- Sort the resulting quadruplet and store in a set to maintain uniqueness.
63+
64+
- **Time Complexity:** O(N³ * log M)
65+
- 3 loops + HashSet lookup + set insertions
66+
67+
- **Space Complexity:** O(M + N)
68+
- Set for results and HashSet for lookup
69+
70+
- **Example/Dry Run:**
71+
72+
Input: `[1, 2, -1, -2, 2, 0, -1]`, Target = 0
73+
Step 1: i = 0, j = 1, k = 2
74+
Sum = 1 + 2 + (-1) = 2, required = -2
75+
Step 2: Check if -2 exists in HashSet
76+
Continue storing valid quads
77+
78+
Output: `[[-2, -1, 1, 2], [-1, -1, 0, 2]]`
79+
80+
---
81+
82+
### 3️⃣ Best / Final Optimized Approach (2 Pointers + Sorting)
83+
84+
- **Explanation:**
85+
- Sort the array first.
86+
- Fix two pointers (`i` and `j`) using nested loops.
87+
- Use two other pointers `k` and `l` to find the remaining two numbers using a two-pointer technique.
88+
- Skip duplicate values to maintain uniqueness.
89+
90+
- **Time Complexity:** O(N³)
91+
- 2 fixed + 2 moving pointers = nested loops with linear scan
92+
93+
- **Space Complexity:** O(M)
94+
- For storing results only
95+
96+
- **Example/Dry Run:**
97+
98+
Input: `[4, 3, 3, 4, 4, 2, 1, 2, 1, 1]`, Target = 9
99+
Sorted: `[1, 1, 1, 2, 2, 3, 3, 4, 4, 4]`
100+
Step 1: i = 0, j = 1, k = 2, l = 9
101+
While k < l, move based on current sum
102+
Skip duplicates after storing a valid quad
103+
104+
Output: `[[1, 1, 3, 4], [1, 2, 2, 4], [1, 2, 3, 3]]`
105+
106+
---
107+
108+
## 📊 Complexity Analysis
109+
110+
| Approach | Time Complexity | Space Complexity |
111+
| ------------- | --------------- | ---------------- |
112+
| Brute Force | O(N⁴ * log M) | O(M) |
113+
| Optimized | O(N³ * log M) | O(M + N) |
114+
| Best Approach | O(N³) | O(M) |
115+
116+
---
117+
118+
## 📉 Optimization Ideas
119+
120+
- Skip duplicates after sorting to avoid storing the same quadruplet multiple times.
121+
- Use long long to avoid integer overflow during summation.
122+
- Efficient pointer movement makes the solution clean and fast.
123+
- Avoid unnecessary lookups by reducing hash operations.
124+
125+
---
126+
127+
## 📌 Example Walkthroughs & Dry Runs
128+
129+
plaintext
130+
Example:
131+
Input: [1, 0, -1, 0, -2, 2], Target = 0
132+
Sorted: [-2, -1, 0, 0, 1, 2]
133+
Step-by-step:
134+
i = 0 (-2), j = 1 (-1), k = 2 (0), l = 5 (2)
135+
Sum = -1 → too small → move k
136+
Sum = 0 → store [-2, -1, 1, 2]
137+
Skip duplicates → next iteration...
138+
139+
Output: [[-2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]]
140+
141+
---
142+
143+
## 🔗 Additional Resources
144+
145+
146+
- [GeeksForGeeks Explanation](https://www.geeksforgeeks.org/find-four-elements-that-sum-to-a-given-value-set-2/)
147+
148+
---
149+
150+
Author: Abdul Wahab
151+
Date: 19/07/2025
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
class Solution {
2+
public:
3+
vector<vector<int>> fourSum(vector<int>& nums, int target) {
4+
int n = nums.size();
5+
vector<vector<int>> ans;
6+
7+
sort(nums.begin(), nums.end());
8+
9+
for (int i = 0; i < n; i++) {
10+
if (i > 0 && nums[i] == nums[i - 1]) continue;
11+
for (int j = i + 1; j < n; j++) {
12+
if (j > i + 1 && nums[j] == nums[j - 1]) continue;
13+
14+
int k = j + 1;
15+
int l = n - 1;
16+
while (k < l) {
17+
long long sum = nums[i];
18+
sum += nums[j];
19+
sum += nums[k];
20+
sum += nums[l];
21+
22+
if (sum == target) {
23+
vector<int> temp = {nums[i], nums[j], nums[k], nums[l]};
24+
ans.push_back(temp);
25+
k++;
26+
l--;
27+
28+
while (k < l && nums[k] == nums[k - 1]) k++;
29+
while (k < l && nums[l] == nums[l + 1]) l--;
30+
}
31+
else if (sum < target) k++;
32+
else l--;
33+
}
34+
}
35+
}
36+
37+
return ans;
38+
}
39+
};
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
class Solution:
2+
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
3+
n = len(nums)
4+
ans = []
5+
nums.sort()
6+
7+
for i in range(n):
8+
if i > 0 and nums[i] == nums[i - 1]:
9+
continue
10+
11+
for j in range(i + 1, n):
12+
if j > i + 1 and nums[j] == nums[j - 1]:
13+
continue
14+
15+
k = j + 1
16+
l = n - 1
17+
18+
while k < l:
19+
current_sum = nums[i] + nums[j] + nums[k] + nums[l]
20+
21+
if current_sum == target:
22+
temp = [nums[i], nums[j], nums[k], nums[l]]
23+
ans.append(temp)
24+
k += 1
25+
l -= 1
26+
27+
while k < l and nums[k] == nums[k - 1]:
28+
k += 1
29+
while k < l and nums[l] == nums[l + 1]:
30+
l -= 1
31+
elif current_sum < target:
32+
k += 1
33+
else:
34+
l -= 1
35+
36+
return ans

0 commit comments

Comments
 (0)