Loading problems...
TL;DR: Use a stack to cancel out valid adjacent pairs of parentheses; the number of characters remaining in the stack represents the minimum additions required.
The problem asks for the minimum number of parentheses we need to insert into a string s to make it valid. A valid parentheses string is one where every opening bracket ( has a corresponding closing bracket ) in the correct order, and valid substrings can be concatenated or nested.
For LeetCode 921, we are given a string containing only ( and ). We can insert characters at any position. The goal is to determine the count of unmatched parentheses that remain after all valid pairs are resolved.
The naive approach relies on the definition of valid parentheses: any valid string is built by recursively adding () pairs. Conversely, we can repeatedly remove valid () pairs from the string until no such pairs exist.
The algorithm works as follows:
"()"."()" substrings remain.python# Pseudo-code for Brute Force while "()" in s: s = s.replace("()", "") return len(s)
Complexity Analysis:
((...))), we might iterate through the string times, and each string replacement operation takes time.The core intuition is that every valid pair () cancels itself out. We can process the string linearly, maintaining a record of "open" expectations.
When we encounter an opening bracket (, we don't know yet if it will be valid. We push it onto a stack (or a waiting list) effectively saying, "I need a closing bracket."
When we encounter a closing bracket ), we check our most recent expectation:
(, we have found a valid pair. We remove the ( from our record (pop from stack). The pair is now resolved and contributes nothing to the final "add" count.( characters (the stack is empty or contains only unmatched )), this ) is unmatched. We record it as needing an opening partner.By the end of the traversal, the stack will contain only the characters that never found a match. The size of this stack is exactly the number of insertions needed.
Visual Description:
Imagine iterating through s = "())".
(. Push to stack. Stack: ['('].). Matches top (. Pop. Stack: [].). Stack empty. Push ). Stack: [')'].
Let's trace the algorithm with the input s = "())(".
stack = []( onto stack.stack = ['(']char = ')':
(. Match found.(.stack = []char = ')':
) onto stack.stack = [')']( onto stack.stack = [')', '(']')' and '('.( at the start and ) at the end).The correctness relies on the invariant that the stack only contains unmatched parentheses in their original relative order.
) encounters a (, they form a valid pair and are removed. This is a safe greedy move because the inner-most pair must be resolved first in any valid parentheses expression.) that enters the stack does so because there was no available ( to match it.( that remains in the stack does so because no subsequent ) appeared to match it.cppclass Solution { public: int minAddToMakeValid(string s) { // Stack to store unmatched parentheses vector<char> stack; for (char c : s) { // If we encounter a closing bracket and the stack has an opening bracket if (c == ')' && !stack.empty() && stack.back() == '(') { stack.pop_back(); // Match found, resolve the pair } else { stack.push_back(c); // No match, push to stack } } // The size of the stack represents the number of unmatched characters return stack.size(); } };
javaclass Solution { public int minAddToMakeValid(String s) { // Stack to store unmatched parentheses // Using Deque as Stack is preferred in Java java.util.Deque<Character> stack = new java.util.ArrayDeque<>(); for (char c : s.toCharArray()) { // If we see a closing bracket, check if we can match it if (c == ')' && !stack.isEmpty() && stack.peek() == '(') { stack.pop(); // Match found, remove the paired opening bracket } else { stack.push(c); // No match, add to unmatched stack } } // Remaining elements are unmatched return stack.size(); } }
pythonclass Solution: def minAddToMakeValid(self, s: str) -> int: stack = [] for char in s: # If current is closing and stack has a matching opening if char == ')' and stack and stack[-1] == '(': stack.pop() # Remove the matched '(' else: stack.append(char) # Push unmatched char # The length of the stack is the number of moves required return len(stack)
s exactly once.((((( or )))))), the stack will store all characters.open_needed, close_needed), but the stack approach is the canonical implementation for this pattern.The Stack - Valid Parentheses Matching pattern is versatile. Understanding the logic in LeetCode 921 allows you to solve several related hard and medium problems:
Mastering the invariant that "stack holds unmatched items" is the key to all these variations.
( and ) and return the difference?Many candidates mistakenly try abs(count('(') - count(')')). This fails for cases like )(. Here, the count of open and close brackets is equal (1 each), so the difference is 0. However, the string is invalid and requires 2 additions (one ( at the start, one ) at the end). Order matters, and the stack preserves order.
While valid for small inputs, repeatedly calling s.replace("()", "") creates a new string in every iteration. If the string is ((...)), this results in complexity. In an interview, linear time is expected for "Minimum Add to Make Parentheses Valid".
Yes. A common confusion is thinking we can only append or prepend. The problem allows insertion at any position. However, the stack solution implicitly handles this: an unmatched ) in the stack means we need to insert a ( before it, and an unmatched ( means we need to insert a ) after it. We don't need to calculate the indices, just the count.