Skip to content

Commit ebd57f0

Browse files
feat: add Valid Parenthesis String problem
- Greedy algorithm implementation - Multiple approaches: DP, Backtracking, Iterative, While loop - O(n) time, O(1) space complexity - Comprehensive explanations and edge cases
1 parent 19b5e10 commit ebd57f0

File tree

2 files changed

+308
-0
lines changed

2 files changed

+308
-0
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Valid Parenthesis String
2+
3+
## Problem Statement
4+
5+
Given a string `s` containing only three types of characters: `'('`, `')'` and `'*'`, return `true` if `s` is valid.
6+
7+
The following rules define a valid string:
8+
9+
- Any left parenthesis `'('` must have a corresponding right parenthesis `')'`.
10+
- Any right parenthesis `')'` must have a corresponding left parenthesis `'('`.
11+
- Left parenthesis `'('` must go before the corresponding right parenthesis `')'`.
12+
- `'*'` could be treated as a single right parenthesis `')'`, a single left parenthesis `'('`, or an empty string.
13+
14+
## Examples
15+
16+
**Example 1:**
17+
```
18+
Input: s = "()"
19+
Output: true
20+
```
21+
22+
## Approach
23+
24+
### Method 1: Greedy Algorithm (Recommended)
25+
1. Track minimum and maximum possible open parentheses
26+
2. Use greedy approach to handle wildcards
27+
3. If min becomes negative, reset to 0
28+
4. Most efficient approach
29+
30+
**Time Complexity:** O(n) - Single pass
31+
**Space Complexity:** O(1) - Two variables
32+
33+
### Method 2: Dynamic Programming
34+
1. Use DP to track all possible states
35+
2. Less efficient than greedy approach
36+
3. More complex implementation
37+
38+
**Time Complexity:** O(n) - Single pass
39+
**Space Complexity:** O(n) - DP array
40+
41+
## Algorithm
42+
43+
```
44+
1. Initialize minOpen = 0, maxOpen = 0
45+
2. For each character in s:
46+
a. If '(': minOpen++, maxOpen++
47+
b. If ')': minOpen--, maxOpen--
48+
c. If '*': minOpen--, maxOpen++
49+
d. If maxOpen < 0: return false
50+
e. If minOpen < 0: minOpen = 0
51+
3. Return minOpen == 0
52+
```
53+
54+
## Key Insights
55+
56+
- **Greedy Choice**: Handle wildcards optimally
57+
- **Local Optimum**: Track possible open parentheses
58+
- **Global Optimum**: Can form valid parentheses
59+
- **Space Optimization**: Use only two variables
60+
61+
## Alternative Approaches
62+
63+
1. **Dynamic Programming**: Use DP array
64+
2. **Backtracking**: Use backtracking to explore all possibilities
65+
3. **Stack**: Use stack to track parentheses
66+
67+
## Edge Cases
68+
69+
- Empty string: Return true
70+
- Single character: Handle appropriately
71+
- All wildcards: Return true
72+
- No wildcards: Use standard parentheses validation
73+
74+
## Applications
75+
76+
- Greedy algorithms
77+
- String validation
78+
- Algorithm design patterns
79+
- Interview preparation
80+
- System design
81+
82+
## Optimization Opportunities
83+
84+
- **Greedy Algorithm**: Most efficient approach
85+
- **Space Optimization**: O(1) space complexity
86+
- **Single Pass**: O(n) time complexity
87+
- **No Extra Space**: Use only two variables
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
/**
2+
* Time Complexity: O(n) - Single pass
3+
* Space Complexity: O(1) - Two variables
4+
*/
5+
class Solution {
6+
public boolean checkValidString(String s) {
7+
int minOpen = 0;
8+
int maxOpen = 0;
9+
10+
for (char c : s.toCharArray()) {
11+
if (c == '(') {
12+
minOpen++;
13+
maxOpen++;
14+
} else if (c == ')') {
15+
minOpen--;
16+
maxOpen--;
17+
} else { // c == '*'
18+
minOpen--;
19+
maxOpen++;
20+
}
21+
22+
if (maxOpen < 0) {
23+
return false;
24+
}
25+
26+
if (minOpen < 0) {
27+
minOpen = 0;
28+
}
29+
}
30+
31+
return minOpen == 0;
32+
}
33+
}
34+
35+
// Alternative approach using Dynamic Programming
36+
class SolutionDP {
37+
public boolean checkValidString(String s) {
38+
int n = s.length();
39+
boolean[][] dp = new boolean[n + 1][n + 1];
40+
dp[0][0] = true;
41+
42+
for (int i = 1; i <= n; i++) {
43+
char c = s.charAt(i - 1);
44+
45+
for (int j = 0; j <= n; j++) {
46+
if (c == '(') {
47+
if (j > 0) {
48+
dp[i][j] = dp[i - 1][j - 1];
49+
}
50+
} else if (c == ')') {
51+
if (j < n) {
52+
dp[i][j] = dp[i - 1][j + 1];
53+
}
54+
} else { // c == '*'
55+
dp[i][j] = dp[i - 1][j];
56+
if (j > 0) {
57+
dp[i][j] = dp[i][j] || dp[i - 1][j - 1];
58+
}
59+
if (j < n) {
60+
dp[i][j] = dp[i][j] || dp[i - 1][j + 1];
61+
}
62+
}
63+
}
64+
}
65+
66+
return dp[n][0];
67+
}
68+
}
69+
70+
// Alternative approach using backtracking
71+
class SolutionBacktracking {
72+
public boolean checkValidString(String s) {
73+
return checkValidStringHelper(s, 0, 0);
74+
}
75+
76+
private boolean checkValidStringHelper(String s, int index, int openCount) {
77+
if (index == s.length()) {
78+
return openCount == 0;
79+
}
80+
81+
char c = s.charAt(index);
82+
83+
if (c == '(') {
84+
return checkValidStringHelper(s, index + 1, openCount + 1);
85+
} else if (c == ')') {
86+
if (openCount <= 0) {
87+
return false;
88+
}
89+
return checkValidStringHelper(s, index + 1, openCount - 1);
90+
} else { // c == '*'
91+
// Try all three possibilities: '(', ')', or empty
92+
return checkValidStringHelper(s, index + 1, openCount + 1) ||
93+
checkValidStringHelper(s, index + 1, openCount - 1) ||
94+
checkValidStringHelper(s, index + 1, openCount);
95+
}
96+
}
97+
}
98+
99+
// Alternative approach using iterative
100+
class SolutionIterative {
101+
public boolean checkValidString(String s) {
102+
int minOpen = 0;
103+
int maxOpen = 0;
104+
105+
for (int i = 0; i < s.length(); i++) {
106+
char c = s.charAt(i);
107+
108+
if (c == '(') {
109+
minOpen++;
110+
maxOpen++;
111+
} else if (c == ')') {
112+
minOpen--;
113+
maxOpen--;
114+
} else { // c == '*'
115+
minOpen--;
116+
maxOpen++;
117+
}
118+
119+
if (maxOpen < 0) {
120+
return false;
121+
}
122+
123+
if (minOpen < 0) {
124+
minOpen = 0;
125+
}
126+
}
127+
128+
return minOpen == 0;
129+
}
130+
}
131+
132+
// Alternative approach using while loop
133+
class SolutionWhileLoop {
134+
public boolean checkValidString(String s) {
135+
int minOpen = 0;
136+
int maxOpen = 0;
137+
int i = 0;
138+
139+
while (i < s.length()) {
140+
char c = s.charAt(i);
141+
142+
if (c == '(') {
143+
minOpen++;
144+
maxOpen++;
145+
} else if (c == ')') {
146+
minOpen--;
147+
maxOpen--;
148+
} else { // c == '*'
149+
minOpen--;
150+
maxOpen++;
151+
}
152+
153+
if (maxOpen < 0) {
154+
return false;
155+
}
156+
157+
if (minOpen < 0) {
158+
minOpen = 0;
159+
}
160+
161+
i++;
162+
}
163+
164+
return minOpen == 0;
165+
}
166+
}
167+
168+
// Alternative approach using enhanced for loop
169+
class SolutionEnhancedForLoop {
170+
public boolean checkValidString(String s) {
171+
int minOpen = 0;
172+
int maxOpen = 0;
173+
174+
for (char c : s.toCharArray()) {
175+
if (c == '(') {
176+
minOpen++;
177+
maxOpen++;
178+
} else if (c == ')') {
179+
minOpen--;
180+
maxOpen--;
181+
} else { // c == '*'
182+
minOpen--;
183+
maxOpen++;
184+
}
185+
186+
if (maxOpen < 0) {
187+
return false;
188+
}
189+
190+
if (minOpen < 0) {
191+
minOpen = 0;
192+
}
193+
}
194+
195+
return minOpen == 0;
196+
}
197+
}
198+
199+
// More concise version
200+
class SolutionConcise {
201+
public boolean checkValidString(String s) {
202+
int minOpen = 0, maxOpen = 0;
203+
for (char c : s.toCharArray()) {
204+
if (c == '(') {
205+
minOpen++;
206+
maxOpen++;
207+
} else if (c == ')') {
208+
minOpen--;
209+
maxOpen--;
210+
} else { // c == '*'
211+
minOpen--;
212+
maxOpen++;
213+
}
214+
215+
if (maxOpen < 0) return false;
216+
if (minOpen < 0) minOpen = 0;
217+
}
218+
219+
return minOpen == 0;
220+
}
221+
}

0 commit comments

Comments
 (0)