Problem
You are given a 0-indexed string s
of even length n
. The string consists of exactly n / 2
opening brackets '['
and n / 2
closing brackets ']'
.
A string is called balanced if and only if:
- It is the empty string, or
- It can be written as
AB
, where bothA
andB
are balanced strings, or - It can be written as
[C]
, whereC
is a balanced string.
You may swap the brackets at any two indices any number of times.
Return the minimum number of swaps to make s
balanced.
Examples
Example 1:
Input s = "][]["
Output 1
Explanation You can make the string balanced by swapping index 0 with index 3.
The resulting string is "[[]]".
Example 2:
Input s = "]]][[["
Output 2
Explanation You can do the following to make the string balanced:
- Swap index 0 with index 4. s = "[]][][".
- Swap index 1 with index 5. s = "[[][]]".
The resulting string is "[[][]]".
Example 3:
Input s = "[]"
Output 0
Explanation The string is already balanced.
Solution
Method 1 - Count the imbalances
Count the number of mismatches, either by using stack OR counter variable, as there is only 1 type of parenthesis. We had done something similar here - Valid Parentheses Problem.
- The given string has equal numbers of
'['
and']'
. - To make the string balanced, we need sufficiently many
'['
before']'
in the sequence. - What causes imbalance? It is a closing bracket before opening bracket.
- The strategy involves tracking imbalances using a counter: when a closing bracket appears without a matching opening bracket, we record an imbalance and look for an opening bracket in future indices to swap it with.
We can ignore the balanced segments of the input string since they don’t affect the overall balance. Once we remove these, the remaining unbalanced brackets will appear as follows:
]]]]]…..[[[[[…..
Given that any pair of brackets can be swapped, the most efficient strategy is to balance two sets of brackets with a single swap (suggesting result = total unbalanced / 2
, which applies to both even and odd lengths). For example:
So, following this, we will notice a pattern (try out the same with different number of mismatches to see the pattern):
swaps: 0, 1, 1, 2, 2, 3, 3..
imbalances: 0, 1, 2, 3, 4, 5, 6...
So, our result (min. swaps) = (mismatches + 1) / 2
Video explanation
Here is the video explaining this method in detail. Please check it out:
Code
Java
public class Solution {
public int minSwaps(String s) {
int imbalance = 0; // To track the maximum imbalance of closing brackets
int count = 0; // To track the current imbalance of brackets
// Iterate through each character in the string
for (char ch : s.toCharArray()) {
if (ch == '[') {
count--; // Decrease count for opening bracket
} else { // char is `']'`
count++; // Increase count for closing bracket
if (count > imbalance) {
imbalance = count; // Update the maximum imbalance
}
}
}
// The minimum number of swaps needed to balance is half the maximum imbalance (rounded up)
return (imbalance + 1) / 2;
}
}
Python
class Solution:
def minSwaps(self, s: str) -> int:
imbalance = 0 # To track the number of swaps needed
count = 0 # To track current imbalance
for char in s:
if char == '[':
count -= 1
else: # char is `']'`
count += 1
if count > imbalance:
imbalance = count
return (imbalance + 1) // 2
Complexity
- ⏰ Time complexity:
O(n)
- 🧺 Space complexity:
O(1)
Method 2 - Greedy
Observations from the Problem:
- The number of
'['
brackets is equal to the number of']'
brackets. - Each bracket has a corresponding counterpart in the string.
- To maintain a balanced string, at any position
i
:- The count of
'['
should be at least equal to the count of']'
. - If the count of
']'
exceeds the count of'['
, a swap is needed.
- The count of
Algorithm:
Use a variable,
balance
, to track if brackets are balanced at any index:- Initialize
balance
to 0.
- Initialize
For an opening bracket
'['
, incrementbalance
by one:- This anticipates a closing bracket later to balance it. For
'['
,balance
becomes +1.
- This anticipates a closing bracket later to balance it. For
For a closing bracket
']'
, decrementbalance
by one:This balances a previously encountered opening bracket. For
']'
,balance
becomes -1.string: [ [ ] ] balance: 1 2 1 0 (at last balance is zero which means all elements are matched)
The key moment for swapping occurs when the count of closing brackets exceeds the number of previously seen opening brackets:
When
balance < 0
orbalance == -1
, swap the current closing bracket with the first'['
encountered from the end.This adjustment changes the balance to 1, and you can continue searching for closing brackets.
string: [ ] ] [ balance : (1) (0) (-1) .... (1) // Swap (-1) with the last (1) to balance it
As soon as we swap the brackets, we need to again set balance to 1 as current bracket is opening ->
'['
= 1
Lets Do a dry run on string : "[ ] ] ] [ [ ] ["
index: 0 1 2 3 4 5 6 7
string : [ ] ] ] [ [ ] [
balance: 1 0 -1 . . . . .
-> swap `']'` at index 2 with first `'['` from last i.e index 7
=> swap = 1 , set balance to 1
After swapping we continue till end until balance does not become -1.
If balance = -1, repeat above steps
index: 0 1 2 3 4 5 6 7
string : [ ] [ ] [ [ ] ]
balance: 1 0 1 0 1 2 1 0
-> This is final value of balance and state string that is balanced
Code
Java
int minSwaps(string s) {
int n = s.size();
int balance = 0, swaps = 0, j=n-1;
char[] arr = s.toCharArray();
for(int i=0; i<n; i++)
{
if(arr[i] == '[') balance++;
else balance--;
if(balance < 0)
{
while(i<j && arr[j] != '[') j--;
swap(arr, i, j);
swaps++;
balance = 1;
}
}
return swaps;
}
Complexity
- ⏰ Time complexity:
O(n)
- 🧺 Space complexity:
O(1)