medium Valid Parenthesis String
Problem Statement
Given a string s containing multiple occurrences of characters: '(', ')' and '*', return true if s is valid. Otherwise, return false.
A string is valid if it follows below rules:
- Any left parenthesis
'('must be closed by corresponding right parenthesis ')'. - Any right parenthesis
')'must have a corresponding left parenthesis'('. '*'can be used as a single left parenthesis')'or a single right parenthesis'('or an empty string"".
Examples
-
Example 1:
- Input: s=
"*())" - Expected Output:
true - Justification: The asterisk can be treated as an open parenthesis, making the string "(())."
- Input: s=
-
Example 2:
- **Input: s =
"((*()**" - Expected Output:
true - **Justification: The first and second asterisks can be treated as close parenthesis, and the third asterisk can be treated as an empty string, resulting in a balanced set of parentheses "(()())."
- **Input: s =
-
Example 3:
- Input: s =
"())*" - Expected Output:
false - Justification: There's no way to interpret the asterisk that would balance the extra close parenthesis at the start.
- Input: s =
Try it yourself
Try solving this question here:
✅ Solution Valid Parenthesis String
Problem Statement
Given a string s containing multiple occurrences of characters: '(', ')' and '*', return true if s is valid. Otherwise, return false.
A string is valid if it follows below rules:
- Any left parenthesis
'('must be closed by corresponding right parenthesis ')'. - Any right parenthesis
')'must have a corresponding left parenthesis'('. '*'can be used as a single left parenthesis')'or a single right parenthesis'('or an empty string"".
Examples
-
Example 1:
- Input: s=
"*())" - Expected Output:
true - Justification: The asterisk can be treated as an open parenthesis, making the string "(())."
- Input: s=
-
Example 2:
- **Input: s =
"((*()**" - Expected Output:
true - **Justification: The first and second asterisks can be treated as close parenthesis, and the third asterisk can be treated as an empty string, resulting in a balanced set of parentheses "(()())."
- **Input: s =
-
Example 3:
- Input: s =
"())*" - Expected Output:
false - Justification: There's no way to interpret the asterisk that would balance the extra close parenthesis at the start.
- Input: s =
Solution
This solution employs a smart strategy to determine if a string with parentheses and asterisks is valid. It navigates through each character, adjusting counts to represent possible states of open parentheses. The core idea revolves around maintaining two counters: a low counter (lo) to represent the minimum possible open parentheses, assuming asterisks are used optimally, and a high counter (hi) to represent the maximum possible open parentheses, assuming all asterisks are treated as open parentheses.
This dual-counter approach captures the flexibility of asterisks, which can act as either open or close parentheses or be omitted. By updating these counters based on current character analysis and ensuring our high counter never drops below zero (which would indicate too many closing parentheses), we maintain a balance check. If, by the end of the string, our low counter resets to zero, it signifies that there's at least one valid way to interpret the string as properly balanced, making this method both efficient and effective in handling the problem's inherent ambiguity.
Step-by-step Algorithm
- Initialize two variables,
loandhi, to zero. These will track the lower and upper bounds of the count of open parentheses. - Iterate through each character of the string
s:- If the character is an open parenthesis
'(', increment bothloandhiby 1. This is because an open parenthesis definitely increases the number of unclosed parentheses. - If the character is a close parenthesis
')', decrement bothloandhiby 1. This reflects closing an open parenthesis. However, sincelorepresents a minimum, it cannot be negative; thus, iflodrops below 0, reset it to 0. - If the character is an asterisk
'*', incrementhiby 1 (as it could act as an open parenthesis) but decrementloby 1 (as it could act as a closing parenthesis). However,lois adjusted to a minimum of 0 to avoid negative values. - After processing each character, check if
hiis less than 0. If true, break the loop as it indicates there are too many closing parentheses, making the string invalid.
- If the character is an open parenthesis
- After iterating through the string, check if
loequals 0. Aloof 0 indicates that there is a valid configuration where all open parentheses can be closed, thus the string is valid.
Algorithm Walkthrough
Given the input "((*()**", let's apply the algorithm:
lo = 0,hi = 0at the start.- First character
'(': increment bothloandhiby 1.lo = 1,hi = 1.
- Second character
'(': increment bothloandhiby 1 again.lo = 2,hi = 2.
- Third character
'*':locould represent a closing parenthesis, so decrement by 1 (but not less than 0), andhicould represent an open parenthesis, so increment by 1.lo = 1(minimum of 1 and not less),hi = 3.
- Fourth character
'(': increment bothloandhiby 1.lo = 2,hi = 4.
- Fifth character
')': decrement bothloandhiby 1.lo = 1,hi = 3.
- Sixth character
'*': treat'*'similarly to the third character; decrementloby 1 (to a minimum of 0) and incrementhi.lo = 0,hi = 4.
- Seventh character
'*': continue with the same approach for'*'.lo = 0,hi = 5.
After completing the iteration, lo is 0, which indicates the string "((*()**" can be valid, assuming asterisks are optimally used either as open parentheses, close parentheses, or not used at all.
Code
class Solution {
public boolean checkValidString(String s) {
int lo = 0, hi = 0;
for (char c : s.toCharArray()) {
lo += c == '(' ? 1 : -1; // Increment lo for '(' and decrement for ')'
hi += c != ')' ? 1 : -1; // Increment hi for '(' and '*', decrement for ')'
if (
hi < 0
) break; // If hi becomes negative, break the loop
lo = Math.max(lo, 0); // Ensure lo doesn't become negative
}
return lo == 0; // If lo is 0, the string is valid
}
public static void main(String[] args) {
Solution solution = new Solution();
// Example 1
String example1 = "*())";
System.out.println(
"Example 1 - Input: " +
example1 +
", Output: " +
solution.checkValidString(example1)
);
// Example 2
String example2 = "((*()**";
System.out.println(
"Example 2 - Input: " +
example2 +
", Output: " +
solution.checkValidString(example2)
);
// Example 3
String example3 = "())*";
System.out.println(
"Example 3 - Input: " +
example3 +
", Output: " +
solution.checkValidString(example3)
);
}
}
Complexity Analysis
- Time Complexity:
, where n is the length of the input string. The algorithm iterates through the string once. - Space Complexity:
, as the algorithm uses only a constant amount of extra space.
🤖 Don't fully get this? Learn it with Claude
Stuck on Valid Parenthesis String? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Progressively stronger hints — you still solve it.
I'm working on the problem **Valid Parenthesis String** (DSA). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
See the technique, not just code.
Explain the optimal approach to **Valid Parenthesis String** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Catch bugs, edge cases, sub-optimality.
I'll paste my solution to **Valid Parenthesis String**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Lock in recognition with look-alikes.
Give me 2 problems that use the SAME underlying pattern as **Valid Parenthesis String**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.