Skip to content

Commit 19b5e10

Browse files
feat: add Partition Labels problem
- Greedy algorithm implementation - Multiple approaches: Two Pointers, Sliding Window, While loop - O(n) time, O(1) space complexity - Comprehensive explanations and edge cases
1 parent b00313b commit 19b5e10

File tree

2 files changed

+273
-0
lines changed

2 files changed

+273
-0
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Partition Labels
2+
3+
## Problem Statement
4+
5+
You are given a string `s`. We want to partition the string into as many parts as possible so that each letter appears in at most one part.
6+
7+
Note that the partition is done so that after concatenating all the parts in order, the resultant string should be `s`.
8+
9+
Return a list of integers representing the size of these parts.
10+
11+
## Examples
12+
13+
**Example 1:**
14+
```
15+
Input: s = "ababcbacadefegdehijhklij"
16+
Output: [9,7,8]
17+
Explanation:
18+
The partition is "ababcbaca", "defegde", "hijhklij".
19+
This is a partition so that each letter appears in at most one part.
20+
A partition like "ababcbacadefegde", "hijhklij" is incorrect, because the letters "a" and "b" appear in both parts.
21+
```
22+
23+
## Approach
24+
25+
### Method 1: Greedy Algorithm (Recommended)
26+
1. Find the last occurrence of each character
27+
2. Use greedy approach to extend partition as far as possible
28+
3. When we reach the end of current partition, add its length
29+
4. Most efficient approach
30+
31+
**Time Complexity:** O(n) - Two passes
32+
**Space Complexity:** O(1) - At most 26 characters
33+
34+
### Method 2: Two Pointers
35+
1. Use two pointers to track partition boundaries
36+
2. Extend partition until all characters are included
37+
3. Less efficient than greedy approach
38+
39+
**Time Complexity:** O(n) - Two passes
40+
**Space Complexity:** O(1) - At most 26 characters
41+
42+
## Algorithm
43+
44+
```
45+
1. Find last occurrence of each character
46+
2. Initialize start = 0, end = 0
47+
3. For i from 0 to n-1:
48+
a. end = max(end, lastOccurrence[s[i]])
49+
b. If i == end:
50+
c. Add partition length to result
51+
d. start = i + 1
52+
4. Return result
53+
```
54+
55+
## Key Insights
56+
57+
- **Greedy Choice**: Extend partition as far as possible
58+
- **Local Optimum**: Include all occurrences of current characters
59+
- **Global Optimum**: Minimize number of partitions
60+
- **Space Optimization**: Use only necessary space
61+
62+
## Alternative Approaches
63+
64+
1. **Two Pointers**: Use two pointers for boundaries
65+
2. **Sliding Window**: Use sliding window technique
66+
3. **Brute Force**: Try all possible partitions
67+
68+
## Edge Cases
69+
70+
- Empty string: Return empty list
71+
- Single character: Return [1]
72+
- All same characters: Return [n]
73+
- No repeated characters: Return [1, 1, ..., 1]
74+
75+
## Applications
76+
77+
- Greedy algorithms
78+
- String partitioning
79+
- Algorithm design patterns
80+
- Interview preparation
81+
- System design
82+
83+
## Optimization Opportunities
84+
85+
- **Greedy Algorithm**: Most efficient approach
86+
- **Space Optimization**: O(1) space complexity
87+
- **Two Passes**: O(n) time complexity
88+
- **No Extra Space**: Use only necessary space
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/**
2+
* Time Complexity: O(n) - Two passes
3+
* Space Complexity: O(1) - At most 26 characters
4+
*/
5+
class Solution {
6+
public List<Integer> partitionLabels(String s) {
7+
List<Integer> result = new ArrayList<>();
8+
int[] lastOccurrence = new int[26];
9+
10+
// Find last occurrence of each character
11+
for (int i = 0; i < s.length(); i++) {
12+
lastOccurrence[s.charAt(i) - 'a'] = i;
13+
}
14+
15+
int start = 0;
16+
int end = 0;
17+
18+
for (int i = 0; i < s.length(); i++) {
19+
end = Math.max(end, lastOccurrence[s.charAt(i) - 'a']);
20+
21+
if (i == end) {
22+
result.add(end - start + 1);
23+
start = i + 1;
24+
}
25+
}
26+
27+
return result;
28+
}
29+
}
30+
31+
// Alternative approach using two pointers
32+
class SolutionTwoPointers {
33+
public List<Integer> partitionLabels(String s) {
34+
List<Integer> result = new ArrayList<>();
35+
int[] lastOccurrence = new int[26];
36+
37+
for (int i = 0; i < s.length(); i++) {
38+
lastOccurrence[s.charAt(i) - 'a'] = i;
39+
}
40+
41+
int left = 0;
42+
int right = 0;
43+
44+
for (int i = 0; i < s.length(); i++) {
45+
right = Math.max(right, lastOccurrence[s.charAt(i) - 'a']);
46+
47+
if (i == right) {
48+
result.add(right - left + 1);
49+
left = i + 1;
50+
}
51+
}
52+
53+
return result;
54+
}
55+
}
56+
57+
// Alternative approach using sliding window
58+
class SolutionSlidingWindow {
59+
public List<Integer> partitionLabels(String s) {
60+
List<Integer> result = new ArrayList<>();
61+
int[] lastOccurrence = new int[26];
62+
63+
for (int i = 0; i < s.length(); i++) {
64+
lastOccurrence[s.charAt(i) - 'a'] = i;
65+
}
66+
67+
int windowStart = 0;
68+
int windowEnd = 0;
69+
70+
for (int i = 0; i < s.length(); i++) {
71+
windowEnd = Math.max(windowEnd, lastOccurrence[s.charAt(i) - 'a']);
72+
73+
if (i == windowEnd) {
74+
result.add(windowEnd - windowStart + 1);
75+
windowStart = i + 1;
76+
}
77+
}
78+
79+
return result;
80+
}
81+
}
82+
83+
// Alternative approach using iterative
84+
class SolutionIterative {
85+
public List<Integer> partitionLabels(String s) {
86+
List<Integer> result = new ArrayList<>();
87+
int[] lastOccurrence = new int[26];
88+
89+
for (int i = 0; i < s.length(); i++) {
90+
lastOccurrence[s.charAt(i) - 'a'] = i;
91+
}
92+
93+
int start = 0;
94+
int end = 0;
95+
96+
for (int i = 0; i < s.length(); i++) {
97+
end = Math.max(end, lastOccurrence[s.charAt(i) - 'a']);
98+
99+
if (i == end) {
100+
result.add(end - start + 1);
101+
start = i + 1;
102+
}
103+
}
104+
105+
return result;
106+
}
107+
}
108+
109+
// Alternative approach using while loop
110+
class SolutionWhileLoop {
111+
public List<Integer> partitionLabels(String s) {
112+
List<Integer> result = new ArrayList<>();
113+
int[] lastOccurrence = new int[26];
114+
115+
for (int i = 0; i < s.length(); i++) {
116+
lastOccurrence[s.charAt(i) - 'a'] = i;
117+
}
118+
119+
int start = 0;
120+
int end = 0;
121+
int i = 0;
122+
123+
while (i < s.length()) {
124+
end = Math.max(end, lastOccurrence[s.charAt(i) - 'a']);
125+
126+
if (i == end) {
127+
result.add(end - start + 1);
128+
start = i + 1;
129+
}
130+
131+
i++;
132+
}
133+
134+
return result;
135+
}
136+
}
137+
138+
// Alternative approach using enhanced for loop
139+
class SolutionEnhancedForLoop {
140+
public List<Integer> partitionLabels(String s) {
141+
List<Integer> result = new ArrayList<>();
142+
int[] lastOccurrence = new int[26];
143+
144+
for (int i = 0; i < s.length(); i++) {
145+
lastOccurrence[s.charAt(i) - 'a'] = i;
146+
}
147+
148+
int start = 0;
149+
int end = 0;
150+
151+
for (int i = 0; i < s.length(); i++) {
152+
end = Math.max(end, lastOccurrence[s.charAt(i) - 'a']);
153+
154+
if (i == end) {
155+
result.add(end - start + 1);
156+
start = i + 1;
157+
}
158+
}
159+
160+
return result;
161+
}
162+
}
163+
164+
// More concise version
165+
class SolutionConcise {
166+
public List<Integer> partitionLabels(String s) {
167+
List<Integer> result = new ArrayList<>();
168+
int[] lastOccurrence = new int[26];
169+
170+
for (int i = 0; i < s.length(); i++) {
171+
lastOccurrence[s.charAt(i) - 'a'] = i;
172+
}
173+
174+
int start = 0, end = 0;
175+
for (int i = 0; i < s.length(); i++) {
176+
end = Math.max(end, lastOccurrence[s.charAt(i) - 'a']);
177+
if (i == end) {
178+
result.add(end - start + 1);
179+
start = i + 1;
180+
}
181+
}
182+
183+
return result;
184+
}
185+
}

0 commit comments

Comments
 (0)