Valid Parenthesis String
Description:
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
Explanation: The '*' can be treated as an empty string.
Example 3:
Input: s = "(*))"
Output: true
Explanation: The '*' can be treated as a left parenthesis '('.
Video Explanation

Approaches:
1. Greedy Approach (Optimal)
Instead of using a stack or dynamic programming, we can solve this problem optimally in a single pass using a greedy approach. Since the '*' character introduces branching possibilities, we can maintain the range of possible open left parentheses at any given step.
We maintain two variables:
minOpen: The minimum possible number of open left parentheses.maxOpen: The maximum possible number of open left parentheses.
- Iterate through the string:
- If we see a
'(': BothminOpenandmaxOpenincrement by 1. - If we see a
')': BothminOpenandmaxOpendecrement by 1. - If we see a
'*': It could be an open parenthesis (maxOpen++), a close parenthesis (minOpen--), or empty (leaves limits unchanged, but effectively expands our range of possibilities).
- If we see a
- Validation Checks:
- If at any point
maxOpen < 0, it means even if we converted every'*'to a'(', we still have too many')'. Thus, the string is invalid, and we immediately returnfalse. - If
minOpen < 0, it means we might have counted too many'*'as')'. A negative open count is impossible in reality, so we just resetminOpento0(essentially treating those extra'*'as empty strings instead).
- If at any point
- Final Check: At the end of the string, if
minOpen == 0, it means we successfully matched all parentheses.
Complexity
- Time Complexity: where is the length of the string
s. We only traverse the string exactly once. - Space Complexity: as we only use two integer variables (
minOpenandmaxOpen) regardless of the size of the input.
Solutions
- C++
- Java
- Python
- JavaScript
class Solution {
public:
bool checkValidString(const string& s) {
int minOpen = 0;
int maxOpen = 0;
for (char c : s) {
if (c == '(') {
minOpen++;
maxOpen++;
} else if (c == ')') {
minOpen--;
maxOpen--;
} else { // c == '*'
minOpen--;
maxOpen++;
}
// If maxOpen is negative, we have too many ')'
if (maxOpen < 0) return false;
// minOpen can't be negative, reset to 0
if (minOpen < 0) minOpen = 0;
}
return minOpen == 0;
}
};
class Solution {
public boolean checkValidString(String s) {
int minOpen = 0;
int maxOpen = 0;
for (char c : s.toCharArray()) {
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '(') {
minOpen++;
maxOpen++;
} else if (c == ')') {
minOpen--;
maxOpen--;
} else { // c == '*'
minOpen--;
maxOpen++;
}
// If maxOpen is negative, we have too many ')'
if (maxOpen < 0) return false;
// minOpen can't be negative, reset to 0
if (minOpen < 0) minOpen = 0;
}
return minOpen == 0;
}
}
class Solution:
def checkValidString(self, s: str) -> bool:
min_open = 0
max_open = 0
for char in s:
if char == '(':
min_open += 1
max_open += 1
elif char == ')':
min_open -= 1
max_open -= 1
else: # char == '*'
min_open -= 1
max_open += 1
# If max_open is negative, we have too many ')'
if max_open < 0:
return False
# min_open can't be negative, reset to 0
if min_open < 0:
min_open = 0
return min_open == 0
/**
* @param {string} s
* @return {boolean}
*/
var checkValidString = function(s) {
let minOpen = 0;
let maxOpen = 0;
for (let i = 0; i < s.length; i++) {
let char = s[i];
if (char === '(') {
minOpen++;
maxOpen++;
} else if (char === ')') {
minOpen--;
maxOpen--;
} else { // char === '*'
minOpen--;
maxOpen++;
}
// If maxOpen is negative, we have too many ')'
if (maxOpen < 0) return false;
// minOpen can't be negative, reset to 0
if (minOpen < 0) minOpen = 0;
}
return minOpen === 0;
};
Done with this topic? Mark it as complete to track your progress.
Related Practice Problems
Handpicked problems sharing similar algorithmic topic tags
Bigrams
Solution for Codeforces 2242A: Bigrams, utilizing a greedy frequency counting approach.
Maximum Length of Pair Chain
Solve the Maximum Length of Pair Chain problem using Dynamic Programming with memoization (LIS variant) and greedy interval scheduling.
RemovevomeR
Solution for Codeforces 2241C: RemovevomeR, utilizing a greedy string observation approach.
Was this page helpful?
Discuss this page
Have a question or spot something confusing in "Valid Parenthesis String"? Ask below. Backed by GitHub Discussions—maintainers receive system notifications directly.