Valid Parenthesis String
You're given a string s made of '(', ')', and '*'. Each '*' can act as '(', as ')', or as nothing. Return true if some choice for the stars makes s a well-formed parenthesis string, where every ')' closes an earlier open '(' and every '(' is closed by the end.
Examples
s = "(*))" returns true
Reading the star as "(" gives "(())".
s = "((*" returns false
Two opens need two closes, and a single star can supply only one.
s = "*(" returns false
The final '(' has nothing after it to close it, whatever the star becomes.
Constraints
- 1 <= s.length <= 100
- s[i] is '(', ')', or '*'.
Hints
With no stars, one counter of open parentheses is enough. What changes when a character could move that counter up, down, or not at all?
Track a range, the minimum and maximum number of open parentheses possible after each character, with a greedy update.
'(' does lo++ and hi++; ')' does lo-- and hi--; '*' does lo-- and hi++. Return false if hi < 0, set lo = max(lo, 0) each step, and return lo == 0 at the end.
Drill This: Your Approach First
Approach
Track the range of possible open counts instead of one count. lo is the fewest opens possible so far and hi is the most. '(' raises both, ')' lowers both, and '*' lowers lo and raises hi. If hi drops below 0, there are too many closes and no choice can recover, so return false. lo is clamped at 0, since a star that would close a nonexistent open can be read as empty instead. At the end, the string is valid when lo is 0. O(n) time, O(1) space.
Time
O(n)
Space
O(1)
Pitfall
Solutions
class Solution {
public boolean checkValidString(String s) {
int lo = 0, hi = 0;
for (char c : s.toCharArray()) {
if (c == '(') {
lo++;
hi++;
} else if (c == ')') {
lo--;
hi--;
} else {
lo--;
hi++;
}
if (hi < 0) return false;
lo = Math.max(lo, 0);
}
return lo == 0;
}
}class Solution:
def checkValidString(self, s: str) -> bool:
lo = hi = 0
for c in s:
if c == "(":
lo += 1
hi += 1
elif c == ")":
lo -= 1
hi -= 1
else:
lo -= 1
hi += 1
if hi < 0:
return False
lo = max(lo, 0)
return lo == 0