Minimum Insertions to Balance a Parentheses String
MedPrompt
Given a parentheses string s containing only the characters '(' and ')'. A parentheses string is balanced if:
- Any left parenthesis
'('must have a corresponding two consecutive right parenthesis'))'. - Left parenthesis
'('must go before the corresponding two consecutive right parenthesis'))'.
In other words, we treat '(' as an opening parenthesis and '))' as a closing parenthesis.
- For example,
"())","())(())))"and"(())())))"are balanced,")()","()))"and"(()))"are not balanced.
You can insert the characters '(' and ')' at any position of the string to balance it if needed.
Return the minimum number of insertions needed to make s balanced.
Example 1:
Input: s = "(()))"
Output: 1
Explanation: The second '(' has two matching '))', but the first '(' has only ')' matching. We need to add one more ')' at the end of the string to be "(())))" which is balanced.Example 2:
Input: s = "())"
Output: 0
Explanation: The string is already balanced.Example 3:
Input: s = "))())("
Output: 3
Explanation: Add '(' to match the first '))', Add '))' to match the last '('.
Constraints:
1 <= s.length <= 105sconsists of'('and')'only.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach iterates through the string while maintaining a count of open parentheses that need to be closed. When a right parenthesis ')' is encountered, we look at the next character to decide if we have a '))' pair or a single ')'. Based on this, we update the count of open parentheses and the number of insertions needed.
Algorithm
- Initialize
insertions = 0andopen_needed = 0. - Iterate through the string
swith an indexi. - If
s[i]is'(':- Increment
open_needed.
- Increment
- If
s[i]is')':- Check if
i+1is within bounds ands[i+1]is also')'. - If yes (we have a
''))'pair):- If
open_needed > 0, it means this pair can close an existing open parenthesis. Decrementopen_needed. - If
open_needed == 0, this pair is unmatched. We need to insert a'('before it. Incrementinsertions. - Increment
ito skip the next')'.
- If
- If no (we have a single
')'):- This single
')'must be part of a''))'pair. We need to insert another')'. Incrementinsertions. - Now that we have a conceptual
''))'pair, we check if it can close an open parenthesis. - If
open_needed > 0, decrementopen_needed. - If
open_needed == 0, we also need to insert a'('. Incrementinsertionsagain.
- This single
- Check if
- After the loop, there might be some remaining
open_needed. Each requires a''))'pair for closing. - Add
open_needed * 2toinsertions. - Return
insertions.
Walkthrough
This approach solves the problem by performing a single pass through the input string. It uses a counter, openNeeded, to keep track of the number of '(' characters that are waiting for a corresponding ''))' closing pair. The core of the logic involves checking for '))' pairs versus single ')' characters and updating the counts accordingly.
When a '(' is found, we simply increment openNeeded. When a ')' is found, we look ahead. If the next character is also a ')', we treat them as a '))' pair. This pair can satisfy one openNeeded requirement. If there are no open parentheses needing to be closed (openNeeded == 0), we must insert a '(', incrementing our insertions count. If we only find a single ')', we know we must insert another ')' to form a '))' pair. After this conceptual insertion, we proceed as if we found a '))' pair.
Finally, after iterating through the entire string, any remaining openNeeded count signifies open parentheses that were never closed. Each of these requires two ')' insertions to form a '))' pair.
class Solution { public int minInsertions(String s) { int insertions = 0; int openNeeded = 0; int i = 0; while (i < s.length()) { if (s.charAt(i) == '(') { openNeeded++; i++; } else { // s.charAt(i) == ')' // Check for a ')' pair if (i + 1 < s.length() && s.charAt(i + 1) == ')') { if (openNeeded > 0) { openNeeded--; } else { // This '))' needs a preceding '(' insertions++; } i += 2; } else { // This is a single ')' // Step 1: We need to insert one ')' to make a pair. insertions++; // Step 2: Now we have a '))' pair. Check if it can close an open '(' if (openNeeded > 0) { openNeeded--; } else { // This new '))' also needs a preceding '(' insertions++; } i++; } } } // Any remaining open brackets need two ')' each. insertions += openNeeded * 2; return insertions; }}Complexity
Time
O(N), where N is the length of the string `s`. We iterate through the string only once.
Space
O(1) extra space, as we only use a few integer variables to keep track of counts, regardless of the input string size.
Trade-offs
Pros
Correct and efficient, solving the problem in a single pass.
Utilizes constant extra space, making it memory-efficient.
Cons
The logic is slightly more complex due to the need for lookahead and handling two separate cases for right parentheses (
')'vs'))').The code can be less intuitive to follow because of the nested conditional statements and manual index management.
This is a more streamlined single-pass approach. Instead of counting open parentheses, we maintain a "balance" counter, let's call it right_needed, which represents the number of right parentheses ')' we currently need to see to keep the string balanced. This simplifies the logic by elegantly handling all cases in a unified manner without explicit lookahead.
Algorithm
- Initialize
insertions = 0andright_needed = 0. - Iterate through each character
cof the strings. - If
cis'(':- If
right_neededis odd, it implies we have a single, unmatched')'from before. To fix this, we must insert one')'to form a''))'pair. This pair will close a previously opened'('. So, we incrementinsertionsand decrementright_needed. - The current
'('requires a''))'pair. So, we add 2 toright_needed.
- If
- If
cis')':- This
')'helps satisfy our requirement. Decrementright_needed. - If
right_neededbecomes negative, it means we have an excess')'without a matching'('. We must insert a'('. This incrementsinsertions. The newly inserted'('itself requires a''))'pair. We have the current')', so we now need one more')'. This meansright_neededshould be 1 (effectively,right_neededgoes from -1 to 1, which isright_needed += 2).
- This
- After the loop,
right_neededholds the count of')'characters that are still required to balance the string. - Add
right_neededtoinsertions. - Return
insertions.
Walkthrough
This optimized approach uses a single counter, rightNeeded, to track the balance of the parentheses. This counter represents the number of ')' characters we expect to see to balance the parentheses encountered so far. This method avoids explicit lookahead and simplifies the code.
The logic is as follows:
- When we see a
'(', we will need two')'characters in the future, so we incrementrightNeededby 2. However, ifrightNeededwas odd before this, it means there was a lone')'waiting for a partner. We must first insert a')'to complete that pair (costing 1 insertion), which in turn closes a pending'('(decrementingrightNeededby 1). - When we see a
')', it fulfills one of the needed right parentheses, so we decrementrightNeeded. IfrightNeededdrops to -1, it means we have an excess')'without a preceding'('. We must insert a'('(costing 1 insertion). This new'('now requires a'))'pair. Since we have the current')', ourrightNeededbecomes 1. - After the loop, any remaining value in
rightNeededrepresents the number of')'we must append to the end to close all remaining open parentheses.
class Solution { public int minInsertions(String s) { int insertions = 0; int rightNeeded = 0; // Tracks the number of ')' needed for (char c : s.toCharArray()) { if (c == '(') { // If rightNeeded is odd, it means we have a single ')' that needs a partner. // We must insert one ')' to make ')).' This ')),' will close a pending '('. if (rightNeeded % 2 != 0) { insertions++; // Insert one ')' rightNeeded--; // One '(' is now balanced } // The current '(' needs two ')' rightNeeded += 2; } else { // c == ')' // We encountered a ')', so our need for ')' decreases. rightNeeded--; // If rightNeeded becomes negative, we have an excess ')'. // We need to insert a '(' to match it. if (rightNeeded < 0) { insertions++; // Insert one '(' // This new '(' also needs a '))'. We have one ')', so we need one more. // So, rightNeeded goes from -1 to 1. rightNeeded += 2; } } } // After iterating, rightNeeded is the number of ')' we still need to insert. insertions += rightNeeded; return insertions; }}Complexity
Time
O(N), where N is the length of the string `s`. The algorithm involves a single pass over the string.
Space
O(1) extra space. Only a constant number of integer variables are used.
Trade-offs
Pros
Optimal time and space complexity.
The logic is more elegant and concise compared to the lookahead approach.
It handles all cases smoothly within a single loop structure without manual index management.
Cons
The logic behind the
right_neededcounter, especially the updates for odd values and when it becomes negative, can be subtle and requires careful thought to understand correctly.
Solutions
Solution
class Solution {public int minInsertions(String s) { int ans = 0, x = 0; int n = s.length(); for (int i = 0; i < n; ++i) { if (s.charAt(i) == '(') { ++x; } else { if (i < n - 1 && s.charAt(i + 1) == ')') { ++i; } else { ++ans; } if (x == 0) { ++ans; } else { --x; } } } ans += x << 1; return ans; }}class Solution {public: int minInsertions(string s) { int ans = 0, x = 0; int n = s.size(); for (int i = 0; i < n; ++i) { if (s[i] == '(') { ++x; } else { if (i < n - 1 && s[i + 1] == ')') { ++i; } else { ++ans; } if (x == 0) { ++ans; } else { --x; } } } ans += x << 1; return ans; }};class Solution: # 待匹配的左括号加 1 x += 1 else : if i < n - 1 and s [ i + 1 ] == ')' : # 有连续两个右括号,i 往后移动 i += 1 else : # 只有一个右括号,插入一个 ans += 1 if x == 0 : # 无待匹配的左括号,插入一个 ans += 1 else : # 待匹配的左括号减 1 x -= 1 i += 1 # 遍历结束,仍有待匹配的左括号,说明右括号不足,插入 x << 1 个 ans += x << 1 return ans def minInsertions(self, s: str) -> int: ans = x = 0 i, n = 0, len(s) while i < n: if s[i] == '(':Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.