LeetCode 678 solution using the Greedy pattern
LeetCode problem link: 678. Valid Parenthesis String
LeetCode 678. Valid Parenthesis String problem description
Medium level problem.
Given a string s containing only three types of characters: '(', ')' and '*', return true if s is valid.
The following rules define a valid string:
- Any left parenthesis
'('must have a corresponding right parenthesis')'. - Any right parenthesis
')'must have a corresponding left parenthesis'('. - Left parenthesis
'('must go before the corresponding right parenthesis')'. '*'could be treated as a single right parenthesis')'or a single left parenthesis'('or an empty string"".
Example 1:
Input: s = "()"
Output: true
Example 2:
Input: s = "(*)"
Output: true
Example 3:
Input: s = "(*))"
Output: true
Example 4:
Input: s = "("
Output: false
Constraints:
1 <= s.length <= 100s[i]is'(',')'or'*'.
LeetCode 678. Valid Parenthesis String problem solution
For solving this problem we can use the Greedy pattern and keep a range of possible numbers of unmatched opening parentheses:
low- the minimum possible number of unmatched'('.high- the maximum possible number of unmatched'('.
For each character:
'('increases bothlowandhigh.')'decreases bothlowandhigh.'*'can be'(',')', or empty, so it decreaseslowand increaseshigh.
low cannot be negative, because a negative number of unmatched opening parentheses is not meaningful, so set it to 0 when it drops below 0.
If high < 0, there are more closing parentheses than can possibly be matched, so return false immediately.
After processing the whole string, the string is valid only if low == 0. This means there is at least one interpretation of all '*' characters that leaves no unmatched opening parentheses.
Patterns | Techniques | Data Structures
Greedy pattern
Complexity
- Time complexity:
O(n)- we scan the string once and do constant work for each character. - Space complexity:
O(1)- only two variables,lowandhigh, are used regardless of the input size.
LeetCode 678. Valid Parenthesis String problem: example
Consider:
s = "(*))"Start with:
low = 0
high = 01. Character '('
An opening parenthesis must increase the number of unmatched opening parentheses:
low = 1
high = 1Possible unmatched '(' counts: [1, 1].
2. Character '*'
'*' can be:
')'→ decrease the count,- empty → keep the count,
'('→ increase the count.
So:
low = 0
high = 2Possible unmatched '(' counts are in the range [0, 2].
3. Character ')'
A closing parenthesis decreases both limits:
low = -1 -> 0
high = 1We clamp low to 0.
Possible unmatched '(' counts: [0, 1].
4. Character ')'
Again decrease both limits:
low = -1 -> 0
high = 0Final state:
low = 0
high = 0Because low == 0, the string is valid.
One valid interpretation is:
(*))
↓
(())Here '*' is treated as '('.
LeetCode 678 C++ solution
class Solution {
public:
bool checkValidString(string s) {
int low = 0;
int high = 0;
// Track the minimum and maximum possible unmatched '('
for(char c : s) {
if(c == '(') {
low++;
high++;
} else if(c == ')') {
low--;
high--;
} else {
// '*' can be ')', empty, or '('
low--;
high++;
}
// The minimum number of unmatched '(' cannot be negative
if(low < 0) low = 0;
// Too many ')' to match in every possible interpretation
if(high < 0) return false;
}
// At least one interpretation must close every '('
return low == 0;
}
};LeetCode 678 Java solution
class Solution {
public boolean checkValidString(String s) {
int low = 0;
int high = 0;
// Track the minimum and maximum possible unmatched '('
for(int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if(c == '(') {
low++;
high++;
} else if(c == ')') {
low--;
high--;
} else {
// '*' can be ')', empty, or '('
low--;
high++;
}
// The minimum number of unmatched '(' cannot be negative
if(low < 0) low = 0;
// Too many ')' to match in every possible interpretation
if(high < 0) return false;
}
// At least one interpretation must close every '('
return low == 0;
}
}LeetCode 678 JavaScript solution
var checkValidString = function(s) {
let low = 0;
let high = 0;
// Track the minimum and maximum possible unmatched '('
for(const c of s) {
if(c === '(') {
low++;
high++;
} else if(c === ')') {
low--;
high--;
} else {
// '*' can be ')', empty, or '('
low--;
high++;
}
// The minimum number of unmatched '(' cannot be negative
if(low < 0) low = 0;
// Too many ')' to match in every possible interpretation
if(high < 0) return false;
}
// At least one interpretation must close every '('
return low === 0;
};LeetCode 678 TypeScript solution
function checkValidString(s: string): boolean {
let low = 0;
let high = 0;
// Track the minimum and maximum possible unmatched '('
for(const c of s) {
if(c === '(') {
low++;
high++;
} else if(c === ')') {
low--;
high--;
} else {
// '*' can be ')', empty, or '('
low--;
high++;
}
// The minimum number of unmatched '(' cannot be negative
if(low < 0) low = 0;
// Too many ')' to match in every possible interpretation
if(high < 0) return false;
}
// At least one interpretation must close every '('
return low === 0;
}LeetCode 678 Python solution
class Solution:
def checkValidString(self, s: str) -> bool:
low = 0
high = 0
# Track the minimum and maximum possible unmatched '('
for c in s:
if c == '(':
low += 1
high += 1
elif c == ')':
low -= 1
high -= 1
else:
# '*' can be ')', empty, or '('
low -= 1
high += 1
# The minimum number of unmatched '(' cannot be negative
if low < 0:
low = 0
# Too many ')' to match in every possible interpretation
if high < 0:
return False
# At least one interpretation must close every '('
return low == 0