Sale: Get 60% Off on all Pro Plans. Buy Now

Valid Parenthesis String

Problem

Given a string s containing only the characters '(', ')', and '*', return true if s is valid. The string is valid if all open parentheses are closed by the corresponding closing parentheses in the correct order, and '*' can represent either '(', ')', or an empty string.

  • 1 ≤ s.length ≤ 100
  • s[i] is '(', ')' or '*'

Example

Input: s = "(*)"
Output: true

The string can be interpreted as "()" by treating '*' as ')'. The algorithm maintains a range of possible counts of unmatched '(' characters as it iterates through the string. For the first character '(', the range becomes [1,1]. For '*', the range expands to [0,2] because '*' can be '(', ')' or empty. For ')', the range contracts to [0,1]. Since the minimum unmatched '(' count is zero at the end, the string is valid.

Approach

Straightforward Solution

A brute-force approach tries all interpretations of '*' as '(', ')', or empty, leading to exponential time complexity due to combinatorial explosion.

Core Observation

The problem requires checking if a string with wildcards can be balanced as parentheses. The wildcard '*' can represent multiple possibilities, so the number of unmatched '(' characters is not a single value but a range of possible counts.

Path to Optimal

Preview

The key insight is to track the minimum and maximum possible number of unmatched '(' characters as the string is processed from left to right…

Full step-by-step walkthrough on Pro

Optimal Approach

Preview

Use two counters, left_min and left_max, to track the minimum and maximum possible unmatched '(' counts. Iterate through the string, updating these counters based on the character…

Full step-by-step walkthrough on Pro

Want the full reasoning chain?

Unlock the complete walkthrough, line-by-line analysis, and recall drill.

Unlock Pro

Time

O(n)

The algorithm makes a single pass through the string, updating counters in constant time per character.

Space

O(1)

Only a fixed number of integer counters are used, regardless of input size.

Pattern Spotlight

Greedy Algorithms (Range Tracking)

When a problem involves ambiguous characters that can represent multiple states, track the range of possible valid states instead of a single state, updating this range greedily to prune impossible paths early.

Solution

Python
1class Solution:
2 def checkValidString(self, s: str) -> bool:
3 left_min, left_max = 0, 0
4
5 for c in s:
6 if c == "(":
7 left_min, left_max = left_min + 1, left_max + 1
8 elif c == ")":
9 left_min, left_max = left_min - 1, left_max - 1
10 else:
11 left_min, left_max = left_min - 1, left_max + 1
12
13 if left_max < 0:
14 return False
15 if left_min < 0:
16 left_min = 0
17
18 return left_min == 0

Step-by-Step Solution

1

Update Possible Unmatched '(' Range for Each Character

5for c in s:
6 if c == "(":
7 left_min, left_max = left_min + 1, left_max + 1
8 elif c == ")":
9 left_min, left_max = left_min - 1, left_max - 1
10 else:
11 left_min, left_max = left_min - 1, left_max + 1
13 if left_max < 0:
14 return False
15 if left_min < 0:
16 left_min = 0

Objective

To maintain and update the minimum and maximum possible counts of unmatched '(' characters as the string is processed.

Key Insight

By interpreting '(' as increasing unmatched count, ')' as decreasing it, and '*' as either increasing, decreasing, or leaving it unchanged, the algorithm updates left_min and left_max accordingly. This range-based tracking efficiently represents all possible interpretations of '*'. Resetting left_min to zero when it becomes negative ensures the range remains valid, reflecting that unmatched '(' cannot be negative.

Interview Quick-Check

Core Logic

Update left_min and left_max based on character: '(' increments both, ')' decrements both, '*' decrements left_min and increments left_max, capturing all wildcard possibilities.

State & Boundaries

If left_max drops below zero, return false immediately as no valid interpretation exists beyond this point.

Common Pitfalls & Bugs

Failing to reset left_min to zero when it becomes negative leads to incorrect invalidation of valid strings.

2

Confirm Validity by Checking Final Unmatched '(' Count

To determine if the string can be valid by verifying if the minimum possible unmatched '(' count is zero after processing all characters.

1 more step with full analysis available on Pro.

Line Analysis

This solution has 5 Critical lines interviewers watch for.

Line 13 Critical
if left_max < 0:

Check if the maximum possible unmatched '(' count is negative.

If left_max is negative, it means even the most optimistic interpretation has more ')' than '(', making the string invalid at this point.

Line 18 Critical
return left_min == 0

Return true if the minimum unmatched '(' count is zero after processing all characters.

A zero minimum unmatched '(' count indicates at least one valid interpretation of '*' exists that balances the parentheses, confirming string validity.

Line 10 Critical
else:

If the character is '*', adjust the range to reflect all possible interpretations.

The wildcard '*' can represent '(', ')', or empty, so left_min decreases by 1 (if '*'' is ')'), and left_max increases by 1 (if '*' is '('), capturing all possibilities.

Full line-by-line criticality + rationale for all 13 lines available on Pro.

Test Your Understanding

Why is it necessary to track both a minimum and maximum possible count of unmatched '(' characters?

See the answer with Pro.

Related Problems

Greedy Algorithms pattern

Don't just read it. Drill it.

Reconstruct Valid Parenthesis String from memory until it sticks. AlgoDrill blanks out key lines and makes you fill them back in, step by step.

Unlock the Valid Parenthesis String drill

or drill a free problem