Valid Parenthesis String - Complete Solution Guide
Valid Parenthesis String is LeetCode problem 678, a Medium level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.
Problem Statement
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
Detailed Explanation
The problem asks us to determine if a string `s` containing only '(', ')', and '*' characters is a valid parenthesis string. A valid string must adhere to the following rules: Each '(' must have a corresponding ')', each ')' must have a corresponding '(', the '(' must appear before the corresponding ')', and a '*' can be treated as a single '(', a single ')', or an empty string. The input is a string `s`, and the output is a boolean: `true` if the string is valid, and `false` otherwise. The string's length will be between 1 and 100 characters.
Solution Approach
The solution utilizes a greedy approach by maintaining two counters: `min_open` and `max_open`. `min_open` represents the minimum possible number of unmatched open parentheses, while `max_open` represents the maximum possible number of unmatched open parentheses. The algorithm iterates through the string. When a '(' is encountered, both `min_open` and `max_open` are incremented. When a ')' is encountered, both are decremented. When a '*' is encountered, `min_open` is decremented (treating '*' as ')') and `max_open` is incremented (treating '*' as '('). If `max_open` becomes negative at any point, it indicates that there are more closing parentheses than can be matched, even with the '*' characters acting as open parentheses. In such cases, the string is invalid. After each step, `min_open` is set to `max(0, min_open)` to ensure it doesn't become negative (a negative value would mean we have more closing than opening parenthesis, which is impossible). Finally, the string is valid only if `min_open` is 0 at the end, indicating that all open parentheses have been matched.
Step-by-Step Algorithm
- Step 1: Initialize `min_open` and `max_open` to 0.
- Step 2: Iterate through the input string `s` character by character.
- Step 3: If the current character is '(', increment both `min_open` and `max_open`.
- Step 4: If the current character is ')', decrement both `min_open` and `max_open`.
- Step 5: If the current character is '*', decrement `min_open` and increment `max_open`.
- Step 6: If `max_open` becomes negative, return `false` because there are more closing parentheses than possible opening parentheses.
- Step 7: Update `min_open` to `max(0, min_open)` to handle cases where '*' or ')' reduce the open count below zero. In such cases, we can assume that these ')' or '*' are compensating for an already matched string.
- Step 8: After iterating through the entire string, return `true` if `min_open` is 0, indicating that all open parentheses have been matched. Otherwise, return `false`.
Key Insights
- Insight 1: The '*' character introduces flexibility, allowing it to be either '(' or ')' or ''
- Insight 2: Instead of trying all possible combinations of '*' (which would be exponential), we can keep track of the range of open parentheses possible at each point in the string.
- Insight 3: Maintain two variables: `min_open` and `max_open`. `min_open` tracks the minimum number of open parentheses needed, and `max_open` tracks the maximum number of open parentheses possible. If `max_open` ever becomes negative, it means there are too many closing parentheses, and the string is invalid. If `min_open` is positive at the end, it means there are too many open parentheses, and the string is invalid. 'min_open' should also be kept non-negative as negative 'min_open' has no valid interpretation.
Complexity Analysis
Time Complexity: O(n)
Space Complexity: O(1)
Topics
This problem involves: String, Dynamic Programming, Stack, Greedy.
Companies
Asked at: Alibaba, Blizzard, Roku, ServiceNow, Tekion.