Given a string s of length 2n containing exactly n '[' and n ']' brackets. Find the minimum number of adjacent swaps needed to make the string balanced.
Note: A string is balanced if every '[' has a matching ']' such that no closing bracket appears before its corresponding opening bracket, and the total counts of both are equal.
Examples:
Input : s = "[]][]["
Output : 2
Explanation : First swap Position 3 and 4 "[][]][" and Second swapPosition 5 and 6 "[][][]"Input : s = "[[][]]"
Output : 0
Explanation : The string is already balanced.
Table of Content
[Naive Approach] Greedy Approach - O(n^2) Time and O(1) Space
We traverse the string while keeping track of the balance between '[' and ']'. Whenever the balance becomes negative, it indicates an excess of ']'. To fix this, we locate the next '[' ahead in the string and swap it leftward to the current position. Each such swap adds the distance between these indices to the total count. After adjusting, the balance is reset, and the traversal continues. The accumulated swap count at the end gives the minimum number of swaps needed to balance the string.
#include <iostream>
#include <string>
using namespace std;
int swapCount(string &s){
int ans=0;
//To store count of '['
int count=0;
int n=s.size();
for(int i=0;i<n;i++){
if(s[i]=='['){
count++;
}
else{
count--;
}
//When count becomes less than 0
if(count<0){
//Start searching for '[' from (i+1)th index
int j=i+1;
while(j<n){
//When jth index contains '['
if(s[j]=='['){
break;
}
j++;
}
//Increment answer
ans+=j-i;
//Set Count to 1 again
count=1;
//Bring character at jth position to ith position
//and shift all character from i to j-1
//towards right
char ch=s[j];
for(int k=j;k>i;k--){
s[k]=s[k-1];
}
s[i]=ch;
}
}
return ans;
}
int main()
{
string s = "[]][][";
cout << swapCount(s) << "\n";
return 0;
}
public class GFG {
static int swapCount(String s) {
int ans = 0;
//To store count of '['
int count = 0;
int n = s.length();
for (int i = 0; i < n; i++) {
if (s.charAt(i) == '[')
count++;
else
count--;
//When count becomes less than 0
if (count < 0) {
//Start searching for '[' from (i+1)th index
int j = i + 1;
while (j < n) {
//When jth index contains '['
if (s.charAt(j) == '[')
break;
j++;
}
//Increment answer
ans += j - i;
//Set Count to 1 again
count = 1;
//Bring character at jth position to ith position
//and shift all character from i to j-1
//towards right
char ch = s.charAt(j);
StringBuilder newString = new StringBuilder(s);
for (int k = j; k > i; k--) {
newString.setCharAt(k, s.charAt(k - 1));
}
newString.setCharAt(i, ch);
s = newString.toString();
}
}
return ans;
}
public static void main(String[] args) {
String s = "[]][][";
System.out.println(swapCount(s));
}
}
def swapCount(s):
ans = 0
# To store the count of '['
count = 0
n = len(s)
for i in range(n):
if s[i] == '[':
count += 1
else:
count -= 1
# When count becomes less than 0
if count < 0:
# Start searching for '[' from (i+1)th index
j = i + 1
while j < n:
# When jth index contains '['
if s[j] == '[':
break
j += 1
# Increment the answer
ans += j - i
# Set count to 1 again
count = 1
# Bring the character at jth position to ith position
# and shift all characters from i to j-1
# towards the right
ch = s[j]
for k in range(j, i, -1):
s[k] = s[k - 1]
s[i] = ch
return ans
if __name__ == "__main__":
s = "[]][]["
print(swapCount(list(s)))
using System;
class GFG{
static int swapCount(string s){
int ans = 0;
// To store count of '['
int count = 0;
int n = s.Length;
for (int i = 0; i < n; i++){
// When '[' encounters
if (s[i] == '[') {
count++;
}
// When ']' encounters
else{
count--;
}
// When count becomes less than 0
if (count < 0){
// Start searching for '[' from (i+1)th index
int j = i + 1;
while (j < n){
// When jth index contains '['
if (s[j] == '['){
break;
}
j++;
}
// Increment answer
ans += j - i;
// Set Count to 1 again
count = 1;
// Bring character at jth position to ith position
// and shift all characters from i to j-1
// towards right
char ch = s[j];
for (int k = j; k > i; k--)
{
s = s.Remove(k, 1);
s = s.Insert(k, s[k - 1].ToString());
}
s = s.Remove(i, 1);
s = s.Insert(i, ch.ToString());
}
}
return ans;
}
static void Main(string[] args)
{
string s = "[]][][";
Console.WriteLine(swapCount(s));
}
}
function swapCount(s) {
let ans = 0;
// To store count of '['
let count = 0;
for (let i = 0; i < s.length; i++) {
if (s[i] === '[') {
count++;
}
else {
count--;
}
// When count becomes less than 0
if (count < 0) {
// Start searching for
// '[' from the beginning
for (let j = 0; j < i; j++) {
// When jth index contains '['
if (s[j] === '[') {
ans += i - j;
// Swap characters to balance the string
let temp = s.substring(0, j) + s[i] + s.substring(j + 1, i) + s[j] + s.substring(i + 1);
s = temp;
break;
}
}
// Reset the count
count = 1;
}
}
return ans;
}
// Driver code
let s1 = "[]][][";
console.log(swapCount(s1));
Output
2
[Better Approach] Optimized Index-Tracking - O(n) Time and O(n) Space
We first store the positions of all '[' in a vector. While scanning the string, we keep a balance counter that goes up for '[' and down for ']'. If the balance becomes negative, it means there are too many ']'. To fix it, we take the next '[' from our vector, swap it forward, and add the swap distance to the answer.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int swapCount(string &s){
// Keep track of '['
vector<int> pos;
for (int i = 0; i < s.length(); ++i)
if (s[i] == '[')
pos.push_back(i);
// To count number of encountered '['
int count = 0;
// To track position of next '[' in pos
int p = 0;
// To store result
int sum = 0;
for (int i = 0; i < s.length(); ++i){
// Increment count and move p to next position
if (s[i] == '[')
{
count++;
p++;
}
else if (s[i] == ']')
count--;
// We have encountered an unbalanced part of string
if (count < 0){
// Increment sum by number of swaps required
// i.e. position of next '[' - current position
sum += pos[p] - i;
swap(s[i], s[pos[p]]);
++p;
// Reset count to 1
count = 1;
}
}
return sum;
}
int main()
{
string s = "[]][][";
cout << swapCount(s) << "\n";
return 0;
}
import java.util.ArrayList;
import java.util.List;
class GFG{
public static int swapCount(String s){
// Keep track of '['
List<Integer> pos = new ArrayList<>();
for(int i = 0; i < s.length(); ++i)
if (s.charAt(i) == '[')
pos.add(i);
// To count number of encountered '['
int count = 0;
// To track position of next '[' in pos
int p = 0;
// To store result
int sum = 0;
char[] S = s.toCharArray();
for(int i = 0; i < s.length(); ++i){
// Increment count and move p
// to next position
if (S[i] == '[')
{
count++;
p++;
}
else if (S[i] == ']')
count--;
// unbalanced part of string
if (count < 0)
{
sum += pos.get(p) - i;
char temp = S[i];
S[i] = S[pos.get(p)];
S[pos.get(p)] = temp;
p++;
// Reset count to 1
count = 1;
}
}
return sum;
}
public static void main(String[] args)
{
String s = "[]][][";
System.out.println(swapCount(s));
}
}
def swapCount(s):
# Keep track of '['
pos = []
for i in range(len(s)):
if(s[i] == '['):
pos.append(i)
# To count number
# of encountered '['
count = 0
# To track position
# of next '[' in pos
p = 0
# To store result
sum = 0
s = list(s)
for i in range(len(s)):
# Increment count and
# move p to next position
if(s[i] == '['):
count += 1
p += 1
elif(s[i] == ']'):
count -= 1
# We have encountered an
# unbalanced part of string
if(count < 0):
# Increment sum by number
# of swaps required
# i.e. position of next
# '[' - current position
sum += pos[p] - i
s[i], s[pos[p]] = (s[pos[p]],
s[i])
p += 1
# Reset count to 1
count = 1
return sum
if __name__ == "__main__":
s = "[]][]["
print(swapCount(s))
using System.IO;
using System;
using System.Collections;
using System.Collections.Generic;
class GFG{
static int swapCount(string s){
// Keep track of '['
List<int> pos = new List<int>();
for(int i = 0; i < s.Length; i++){
if (s[i] == '['){
pos.Add(i);
}
}
// To count number of encountered '['
int count = 0;
// To track position of next '[' in pos
int p = 0;
// To store result
int sum = 0;
char[] S = s.ToCharArray();
for(int i = 0; i < S.Length; i++){
// Increment count and move p
// to next position
if (S[i] == '['){
count++;
p++;
}
else if (S[i] == ']'){
count--;
}
// We have encountered an
// unbalanced part of string
if (count < 0){
// Increment sum by number of
// swaps required i.e. position
// of next '[' - current position
sum += pos[p]-i;
char temp = S[i];
S[i] = S[pos[p]];
S[pos[p]] = temp;
++p;
// Reset count to 1
count = 1;
}
}
return sum;
}
static void Main(){
string s = "[]][][";
Console.WriteLine(swapCount(s));
}
}
function swapCount(s){
// Keep track of '['
let pos = [];
for(let i = 0; i < s.length; ++i)
if (s[i] == '[')
pos.push(i);
// To count number of encountered '['
let count = 0;
// To track position of next '[' in pos
let p = 0;
// To store result
let sum = 0;
let S = s.split('');
for(let i = 0; i < s.length; ++i){
// Increment count and move p
// to next position
if (S[i] == '['){
count++;
p++;
}
else if (S[i] == ']')
count--;
// We have encountered an
// unbalanced part of string
if (count < 0) {
// Increment sum by number of
// swaps required i.e. position
// of next '[' - current position
sum += pos[p] - i;
let temp = S[i];
S[i] = S[pos[p]];
S[pos[p]] = temp;
++p;
// Reset count to 1
count = 1;
}
}
return sum;
}
// Driver Code
let s = "[]][][";
console.log(swapCount(s));
Output
2
[Expected Approach] Imbalance Counting Method - O(n) Time and O(1) Space
We traverse the string from left to right while keeping track of how many [ and ] we have seen. Whenever the number of ] becomes greater than [, we say there is an imbalance. Later, when we encounter a [, if imbalance > 0, it means this [ must be shifted left to balance one of the earlier unmatched ]. The number of swaps needed is exactly equal to the current imbalance, so we add it to our total swap count and decrease the imbalance by 1. By the end of the scan, the accumulated count gives the minimum adjacent swaps required.
#include <iostream>
#include <string>
using namespace std;
int swapCount(string &s) {
int countLeft = 0, countRight = 0;
// swap stores the number of swaps
// required imbalance maintains
int swap = 0 , imbalance = 0;
for(int i = 0; i < s.length(); i++){
if (s[i] == '['){
countLeft++;
if (imbalance > 0){
// swaps count is last swap count + total
// number imbalanced brackets
swap += imbalance;
// imbalance decremented by 1 as it solved
// only one imbalance of Left and Right
imbalance--;
}
}
else if(s[i] == ']' ){
countRight++;
// imbalance is reset to current difference
// between Left and Right brackets
imbalance = (countRight - countLeft);
}
}
return swap;
}
int main(){
string s = "[]][][";
cout << swapCount(s) << endl;
return 0;
}
public class GFG{
static int swapCount(String s){
char[] chars = s.toCharArray();
int countLeft = 0, countRight = 0;
// swap stores the number of swaps required
//imbalance maintains the number of imbalance pair
int swap = 0 , imbalance = 0;
for(int i =0; i< chars.length; i++) {
if(chars[i] == '['){
countLeft++;
if(imbalance > 0){
// swaps count is last swap count + total
// number imbalanced brackets
swap += imbalance;
// imbalance decremented by 1 as it solved
// only one imbalance of Left and Right
imbalance--;
}
} else if(chars[i] == ']' ) {
countRight++;
// imbalance is reset to current difference
// between Left and Right brackets
imbalance = (countRight-countLeft);
}
}
return swap;
}
public static void main(String args[])
{
String s = "[]][][";
System.out.println(swapCount(s) );
}
}
def swapCount(s):
# Swap stores the number of swaps
# required imbalance maintains the
# number of imbalance pair
swap = 0
imbalance = 0;
for i in s:
if i == '[':
# Decrement the imbalance
imbalance -= 1
else:
# Increment imbalance
imbalance += 1
if imbalance > 0:
swap += imbalance
return swap
def swapCount(s):
# Keep track of '['
pos = []
for i in range(len(s)):
if(s[i] == '['):
pos.append(i)
# To count number
# of encountered '['
count = 0
# To track position
# of next '[' in pos
p = 0
# To store result
sum = 0
s = list(s)
for i in range(len(s)):
# Increment count and
# move p to next position
if(s[i] == '['):
count += 1
p += 1
elif(s[i] == ']'):
count -= 1
# We have encountered an
# unbalanced part of string
if(count < 0):
# Increment sum by number
# of swaps required
# i.e. position of next
# '[' - current position
sum += pos[p] - i
s[i], s[pos[p]] = (s[pos[p]],
s[i])
p += 1
# Reset count to 1
count = 1
return sum
if __name__ == "__main__":
s = "[]][]["
print(swapCount(s))
using System;
class GFG{
public static int swapCount(string s){
char[] chars = s.ToCharArray();
int countLeft = 0, countRight = 0;
// swap stores the number of swaps
// required imbalance maintains the
// number of imbalance pair
int swap = 0, imbalance = 0;
for (int i = 0; i < chars.Length; i++){
if (chars[i] == '['){
countLeft++;
if (imbalance > 0){
// swaps count is last swap count + total
// number imbalanced brackets
swap += imbalance;
// imbalance decremented by 1 as it solved
// only one imbalance of Left and Right
imbalance--;
}
}
else if (chars[i] == ']'){
countRight++;
// imbalance is reset to current difference
// between Left and Right brackets
imbalance = (countRight - countLeft);
}
}
return swap;
}
public static void Main(string[] args)
{
string s = "[]][][";
Console.WriteLine(swapCount(s));
}
}
function swapCount(s) {
let chars = s.split('');
let countLeft = 0, countRight = 0;
// swap stores the number of swaps
// required imbalance maintains the
// number of imbalance pair
let swap = 0, imbalance = 0;
for (let i = 0; i < chars.length; i++){
if (chars[i] == '['){
countLeft++;
if (imbalance > 0){
// swaps count is last swap count + total
// number imbalanced brackets
swap += imbalance;
// imbalance decremented by 1 as it solved
// only one imbalance of Left and Right
imbalance--;
}
}
else if (chars[i] == ']'){
countRight++;
// imbalance is reset to current difference
// between Left and Right brackets
imbalance = (countRight - countLeft);
}
}
return swap;
}
// Driven Code
let s = "[]][][";
console.log(swapCount(s));
Output
2