
Problem Statement
In this task, we're working with a string s
that comprises parentheses ('('
and ')'
) as well as lowercase English characters. The objective is to modify the string by removing the least number of parentheses to make the string valid according to the rules of a "valid parentheses string." These rules define that a string is valid if it is either an empty string, a string that only contains lowercase characters, or a string that can be decomposed into subsections that either stand alone as valid strings or are enclosed valid strings within parentheses. The solution should return any version of a valid string that can be achieved through the minimal removal of parentheses.
Examples
Example 1
Input:
s = "val(i(d)e)n)"
Output:
"val(i(d)e)n"
Explanation:
"val(i(de)en)", "val(id(e)n)" would also be accepted.
Example 2
Input:
s = "a)b(c)d"
Output:
"ab(c)d"
Example 3
Input:
s = "))(("
Output:
""
Explanation:
An empty string is also valid.
Constraints
1 <= s.length <= 10⁵
s[i]
is either'('
,')'
, or a lowercase English letter.
Approach and Intuition
To solve this problem effectively, we can rely on a stack-based approach combined with two-pass processing of the string:
First Pass: Identify Excessive Closing Brackets
Initialize an empty stack and iterate through the string.
For each character:
- If it is
'('
, push it onto the stack. - If it is
')'
, check if the stack is non-empty and the top is'('
. If true, pop the stack (i.e., you found a matching pair); otherwise, mark this')'
as redundant by replacing it with a special character (like'*'
) in the string.
- If it is
By the end of this pass, all unneeded
')'
characters are marked.
Second Pass: Identify Excessive Opening Brackets
Clear the stack and traverse the string again, this time from right to left.
For each character:
- If it is
')'
, push it onto the stack. - If it is
'('
, check if the stack is non-empty and the top is')'
. If true, pop the stack; otherwise, mark this'('
as redundant by replacing it with'*'
.
- If it is
Unmatched
'('
characters are marked by the end of this pass.
Construct the Valid String
- Traverse the modified string and build a new string by skipping all
'*'
characters. This string is now a valid parentheses string.
- Traverse the modified string and build a new string by skipping all
Key Points to Consider:
- Each removed character should be counted to ensure that the removal is minimal.
- The stack helps in tracking unmatched parentheses effectively.
- The approach is efficient with a linear time complexity
O(n)
due to the two linear passes over the string. Given that the string manipulation for each character is constant time, this is optimal.
Using the examples given, it's clear how this method systematically identifies and removes the necessary characters to enforce the validity of the string while adhering to the requirement of minimal removal. This method is robust and handles all edge cases such as strings of only parentheses or mixed with letters.
Solutions
- Java
- Python
class Solution {
public String makeValid(String inputString) {
// First pass: Remove excess closing parentheses
StringBuilder tempBuilder = new StringBuilder();
int countOpen = 0;
int netBalance = 0;
for (int index = 0; index < inputString.length(); index++) {
char character = inputString.charAt(index);
if (character == '(') {
countOpen++;
netBalance++;
} else if (character == ')') {
if (netBalance == 0) continue;
netBalance--;
}
tempBuilder.append(character);
}
// Second pass: Remove excess opening parentheses
StringBuilder finalResult = new StringBuilder();
int keepOpen = countOpen - netBalance;
for (int index = 0; index < tempBuilder.length(); index++) {
char character = tempBuilder.charAt(index);
if (character == '(') {
keepOpen--;
if (keepOpen < 0) continue;
}
finalResult.append(character);
}
return finalResult.toString();
}
}
The given Java solution addresses the problem of removing the minimum number of parentheses to make a string of parentheses valid. The approach uses a two-pass method to ensure the string is valid without unnecessary parentheses while maintaining the original order of characters.
In the first pass:
- Traverse the input string character by character using a
StringBuilder
to construct an intermediate result. - Maintain a balance (
netBalance
) of open to close parentheses. When encountering an open parenthesis '(', increase bothcountOpen
andnetBalance
. For a close parenthesis ')', decreasenetBalance
only if it's greater than zero, ensuring not to account for unmatched ')' characters.
- Traverse the input string character by character using a
In the second pass:
- Construct the final string from the intermediate string built in the first pass.
- Use another
StringBuilder
, and process each character. - Allow only the necessary number of '(' based on the balance left from the first pass (
keepOpen
calculated ascountOpen - netBalance
). - Append only valid parentheses to the final result, thus ensuring all unbalanced '(' are omitted.
The resulting string returned by the method makeValid
is the input string stripped of the minimum number of parentheses required to make its structure valid, fulfilling the problem's requirements efficiently.
class Solution:
def makeValidParentheses(self, input_str: str) -> str:
# First phase: erase extraneous ")"
processed_chars = []
count_balance = 0
count_open_parens = 0
for char in input_str:
if char == "(":
count_balance += 1
count_open_parens += 1
if char == ")":
if count_balance == 0:
continue
count_balance -= 1
processed_chars.append(char)
# Second phase: erase extra "(" starting from the end
final_result = []
opens_remaining = count_open_parens - count_balance
for char in processed_chars:
if char == "(":
opens_remaining -= 1
if opens_remaining < 0:
continue
final_result.append(char)
return "".join(final_result)
The Python code provided defines a method named makeValidParentheses
within the Solution
class, aiming to solve the problem of ensuring parentheses in a string are properly balanced. This is done via a two-phase process, designed to first remove extraneous closing parentheses and then to identify and remove surplus opening parentheses. Here's a breakdown of how this solution operates:
- The function accepts an
input_str
argument, representing the initial string containing potentially unbalanced parentheses. - Initialization: Several variables are set up:
processed_chars
: a list to hold characters that either pass the validity check or will be further checked in the second phase.count_balance
: a counter used to ensure there are no more right parentheses being closed than the left ones opened.count_open_parens
: a counter to track the number of opening parentheses.
- First Phase - Removing Extraneous Closing Parentheses (
)
)- Iterate through each character in the
input_str
. - If an opening parenthesis is encountered, increment both
count_balance
andcount_open_parens
. - If a closing parenthesis is encountered, check whether there is a preceding unmatched opening parenthesis (
count_balance
is non-zero). If not, this closing parenthesis is skipped. - Add permissible characters to the
processed_chars
list.
- Iterate through each character in the
- Second Phase - Adjusting Unmatched Opening Parentheses (
(
)- Initialize
opens_remaining
to the difference between total opening parentheses and matched closing ones. - Iterate through the
processed_chars
. - For each opening parenthesis, decrement
opens_remaining
. If decrementing results in a negative value, skip adding this character; it means this opening parenthesis doesn't have a matching closing one. - Append all other characters to the final results list.
- Initialize
- Compile the Result:
- Convert the list of valid characters (
final_result
) back into a string and return it.
- Convert the list of valid characters (
This approach efficiently resolves the parentheses balancing by minimizing the number of passes over the string and using data structures that facilitate fast updates and checks.
No comments yet.