Skip to content

Commit cbc97df

Browse files
Merge branch 'master' into feature/14-longest-common-prefix
2 parents c043d7a + 4ec8fe3 commit cbc97df

File tree

50 files changed

+2792
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2792
-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
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# 152. Maximum Product Subarray
2+
3+
**Difficulty:** Medium
4+
**Category:** Arrays, Dynamic Programming
5+
**Leetcode Link:** [Problem Link](https://leetcode.com/problems/maximum-product-subarray/)
6+
7+
---
8+
9+
## 📝 Introduction
10+
11+
Given an integer array `nums`, find a contiguous non-empty subarray within the array that has the largest product, and return the product.
12+
13+
The problem requires handling negative numbers and zeros, which can disrupt the product and reset subarrays. A subarray must be contiguous, and the result must be the largest product among all possible subarrays.
14+
15+
Constraints:
16+
- 1 <= nums.length <= 2 * 10⁴
17+
- -10 ≤ nums[i] ≤ 10
18+
- The product of any prefix or suffix of nums is guaranteed to fit in a 32-bit integer.
19+
20+
---
21+
22+
## 💡 Approach & Key Insights
23+
24+
To solve this problem, we evaluate various approaches:
25+
26+
- Brute-force: Try all subarrays and compute their products.
27+
- Optimized: Observe properties of negative numbers and zeros.
28+
- Best: Use a modified version of Kadane’s algorithm that tracks both max and min products to handle sign flips.
29+
30+
Key observations:
31+
- Positive product → Keep multiplying.
32+
- Negative product → Might become maximum when multiplied with another negative.
33+
- Zeros → Break the subarray and reset.
34+
35+
---
36+
37+
## 🛠️ Breakdown of Approaches
38+
39+
### 1️⃣ Brute Force / Naive Approach
40+
41+
- **Explanation:**
42+
Generate all possible subarrays using two nested loops. For each subarray, calculate the product of its elements. Keep track of the maximum product seen so far.
43+
44+
- **Time Complexity:** O(N²) - N starting points and N subarray lengths
45+
- **Space Complexity:** O(1) - No extra space used beyond variables
46+
47+
- **Example/Dry Run:**
48+
49+
Example input: [2, 3, -2, 4]
50+
Subarrays:
51+
- [2] → 2
52+
- [2, 3] → 6
53+
- [2, 3, -2] → -12
54+
- [3, -2] → -6
55+
- [-2, 4] → -8
56+
Max = 6
57+
58+
---
59+
60+
### 2️⃣ Optimized Approach
61+
62+
- **Explanation:**
63+
Based on the number of negative elements:
64+
- If all positives → result is the product of entire array.
65+
- If even number of negatives → product of entire array is positive.
66+
- If odd number of negatives → remove one negative (either from start or end) to make the product positive.
67+
68+
Handle 0s by splitting the array into subarrays and applying the above logic on each.
69+
70+
- **Algorithm:**
71+
- Loop through the array, tracking prefix and suffix products.
72+
- Reset the prefix/suffix product to 1 when hitting zero.
73+
- Track the maximum of all such segment products.
74+
75+
- **Time Complexity:** O(N) - Single pass
76+
- **Space Complexity:** O(1) - Only scalar variables used
77+
78+
- **Example/Dry Run:**
79+
80+
Input: [-2, 3, 4, -1, 0, -2, 3, 1, 4, 0, 4, 6, -1, 4]
81+
Break on zeros → {[−2,3,4,−1], [−2,3,1,4], [4,6,−1,4]}
82+
Apply logic on each subarray
83+
Answer = max of all segment max products
84+
85+
---
86+
87+
### 3️⃣ Best / Final Optimized Approach (Kadane-style)
88+
89+
- **Explanation:**
90+
Track the maximum and minimum product ending at the current index. Negative numbers can flip max to min and vice versa. This ensures handling of alternating signs.
91+
92+
- **Algorithm:**
93+
- Initialize prod1 = prod2 = result = nums[0]
94+
- Traverse the array from index 1:
95+
- temp = max(current, current × prod1, current × prod2)
96+
- prod2 = min(current, current × prod1, current × prod2)
97+
- prod1 = temp
98+
- result = max(result, prod1)
99+
100+
- **Time Complexity:** O(N) - Single loop
101+
- **Space Complexity:** O(1) - Constant number of variables
102+
103+
- **Example/Dry Run:**
104+
105+
Input: [1, 2, -3, 0, -4, -5]
106+
Step 1: prod1 = prod2 = result = 1
107+
i = 1: nums[i] = 2 → temp = max(2, 2×1, 2×1) = 2
108+
→ prod1 = 2, prod2 = 2, result = 2
109+
i = 2: nums[i] = -3 → temp = max(-3, -6, -6) = -3
110+
→ prod1 = -3, prod2 = -6, result = 2
111+
i = 3: nums[i] = 0 → temp = 0 → reset
112+
i = 4: nums[i] = -4 → etc.
113+
Final result: 20
114+
115+
---
116+
117+
## 📊 Complexity Analysis
118+
119+
| Approach | Time Complexity | Space Complexity |
120+
| ------------- | --------------- | ---------------- |
121+
| Brute Force | O(N²) | O(1) |
122+
| Optimized | O(N) | O(1) |
123+
| Best Approach | O(N) | O(1) |
124+
125+
---
126+
127+
## 📉 Optimization Ideas
128+
129+
- Use rolling variables instead of arrays to track max/min products.
130+
- Restart subarray product after encountering 0 to ensure correct segmentation.
131+
- Can further optimize by using prefix/suffix scans with early exits.
132+
133+
---
134+
135+
## 📌 Example Walkthroughs & Dry Runs
136+
137+
plaintext
138+
Example:
139+
Input: [2, 3, -2, 4]
140+
Process:
141+
→ 2 → max = 2
142+
→ 2×3 = 6 → max = 6
143+
→ 6×(-2) = -12 → becomes min
144+
→ restart with 4 → max = 6
145+
Output: 6
146+
147+
Another:
148+
Input: [1, 2, -3, 0, -4, -5]
149+
→ Subarray after 0 = [-4, -5] → product = 20
150+
Output: 20
151+
152+
---
153+
154+
## 🔗 Additional Resources
155+
156+
- [Kadane’s Algorithm for Maximum Sum](https://en.wikipedia.org/wiki/Maximum_subarray_problem)
157+
158+
---
159+
160+
Author: Abdul Wahab
161+
Date: 19/07/2025
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class Solution {
2+
public:
3+
int maxProduct(vector<int>& nums) {
4+
int prod1 = nums[0]; // max product ending here
5+
int prod2 = nums[0]; // min product ending here
6+
int result = nums[0];
7+
8+
for (int i = 1; i < nums.size(); i++) {
9+
int temp = max({nums[i], prod1 * nums[i], prod2 * nums[i]});
10+
prod2 = min({nums[i], prod1 * nums[i], prod2 * nums[i]});
11+
prod1 = temp;
12+
13+
result = max(result, prod1);
14+
}
15+
16+
return result;
17+
}
18+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class Solution {
2+
public int maxProduct(int[] nums) {
3+
int prod1 = nums[0]; // max product ending here
4+
int prod2 = nums[0]; // min product ending here
5+
int result = nums[0];
6+
7+
for (int i = 1; i < nums.length; i++) {
8+
int temp = Math.max(nums[i], Math.max(prod1 * nums[i], prod2 * nums[i]));
9+
prod2 = Math.min(nums[i], Math.min(prod1 * nums[i], prod2 * nums[i]));
10+
prod1 = temp;
11+
12+
result = Math.max(result, prod1);
13+
}
14+
15+
return result;
16+
}
17+
}

0 commit comments

Comments
 (0)