Minimum number of given operations required to make two strings equal
Last Updated :
21 Mar, 2023
Given two strings A and B, both strings contain characters a and b and are of equal lengths. There is one _ (empty space) in both the strings. The task is to convert first string into second string by doing the minimum number of the following operations:
- If _ is at position i then _ can be swapped with a character at position i+1 or i-1.
- If characters at positions i+1 and i+2 are different then _ can be swapped with a character at position i+1 or i+2.
- Similarly, if characters at positions i-1 and i-2 are different then _ can be swapped with a character at position i-1 or i-2.
Examples:
Input: A = "aba_a", B = "_baaa"
Output: 2
Move 1 : A = "ab_aa" (Swapped A[2] with A[3]) Move 2 : A = "_baaa" (Swapped A[0] with A[2])
Input: A = "a_b", B = "ab_"
Output: 1
Source: Directi Interview Set 7
Approach:
- Apply a simple Breadth First Search over the string and an element of the queue used for BFS will contain the pair str, pos where pos is the position of _ in the string str.
- Also maintain a map vis which will store the string as key and the minimum moves to get to the string as value.
- For every string str from the queue, generate a new string tmp based on the four conditions given and update the vis map as vis[tmp] = vis[str] + 1.
- Repeat the above steps until the queue is empty or the required string is generated i.e. tmp == B
- If the required string is generated then return vis[str] + 1 which is the minimum number of operations required to change A to B.
Below is the implementation of the above approach:
C++
// C++ implementation of the above approach
#include <bits/stdc++.h>
using namespace std;
// Function to return the minimum number of
// operations to convert string A to B
int minOperations(string s, string f)
{
// If both the strings are equal then
// no operation needs to be performed
if (s == f)
return 0;
unordered_map<string, int> vis;
int n;
n = s.length();
int pos = 0;
for (int i = 0; i < s.length(); i++) {
if (s[i] == '_') {
// store the position of '_'
pos = i;
break;
}
}
// to store the generated string at every
// move and the position of '_' within it
queue<pair<string, int> > q;
q.push({ s, pos });
// vis will store the minimum operations
// to reach that particular string
vis[s] = 0;
while (!q.empty()) {
string ss = q.front().first;
int pp = q.front().second;
// minimum moves to reach the string ss
int dist = vis[ss];
q.pop();
// try all 4 possible operations
// if '_' can be swapped with
// the character on it's left
if (pp > 0) {
// swap with the left character
swap(ss[pp], ss[pp - 1]);
// if the string is generated
// for the first time
if (!vis.count(ss)) {
// if generated string is
// the required string
if (ss == f) {
return dist + 1;
break;
}
// update the distance for the
// currently generated string
vis[ss] = dist + 1;
q.push({ ss, pp - 1 });
}
// restore the string before it was
// swapped to check other cases
swap(ss[pp], ss[pp - 1]);
}
// swap '_' with the character
// on it's right this time
if (pp < n - 1) {
swap(ss[pp], ss[pp + 1]);
if (!vis.count(ss)) {
if (ss == f) {
return dist + 1;
break;
}
vis[ss] = dist + 1;
q.push({ ss, pp + 1 });
}
swap(ss[pp], ss[pp + 1]);
}
// if '_' can be swapped
// with the character 'i+2'
if (pp > 1 && ss[pp - 1] != ss[pp - 2]) {
swap(ss[pp], ss[pp - 2]);
if (!vis.count(ss)) {
if (ss == f) {
return dist + 1;
break;
}
vis[ss] = dist + 1;
q.push({ ss, pp - 2 });
}
swap(ss[pp], ss[pp - 2]);
}
// if '_' can be swapped
// with the character at 'i+2'
if (pp < n - 2 && ss[pp + 1] != ss[pp + 2]) {
swap(ss[pp], ss[pp + 2]);
if (!vis.count(ss)) {
if (ss == f) {
return dist + 1;
break;
}
vis[ss] = dist + 1;
q.push({ ss, pp + 2 });
}
swap(ss[pp], ss[pp + 2]);
}
}
}
// Driver code
int main()
{
string A = "aba_a";
string B = "_baaa";
cout << minOperations(A, B);
return 0;
}
Java
// Java implementation of the above approach
import java.util.*;
class GFG {
// Function to return the minimum number of
// operations to convert string A to B
static int minOperations(String s, String f)
{
// If both the strings are equal then
// no operation needs to be performed
if (s.equals(f))
return 0;
Map<String, Integer> vis = new HashMap<>();
int n;
n = s.length();
int pos = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '_') {
// store the position of '_'
pos = i;
break;
}
}
// to store the generated string at every
// move and the position of '_' within it
Queue<Map.Entry<String, Integer>> q
= new LinkedList<Map.Entry<String, Integer>>();
q.add(new AbstractMap.SimpleEntry<String, Integer>(s, pos));
// vis will store the minimum operations
// to reach that particular string
vis.put(s, 0);
while (!q.isEmpty()) {
String ss = q.peek().getKey();
int pp = q.peek().getValue();
// minimum moves to reach the string ss
int dist = vis.get(ss);
q.remove();
// try all 4 possible operations
// if '_' can be swapped with
// the character on it's left
if (pp > 0) {
// swap with the left character
char[] ch = ss.toCharArray();
char temp = ch[pp];
ch[pp] = ch[pp - 1];
ch[pp - 1] = temp;
ss = String.valueOf(ch);
// if the string is generated
// for the first time
if (!vis.containsKey(ss)) {
// if generated string is
// the required string
if (ss.equals(f)) {
return dist + 1;
}
// update the distance for the
// currently generated string
vis.put(ss, dist + 1);
q.add(new AbstractMap.SimpleEntry<String, Integer>(ss, pp - 1));
}
// restore the string before it was
// swapped to check other cases
ch = ss.toCharArray();
temp = ch[pp];
ch[pp] = ch[pp - 1];
ch[pp - 1] = temp;
ss = String.valueOf(ch);
}
// swap '_' with the character
// on it's right this time
if (pp < n - 1) {
char[] ch = ss.toCharArray();
char temp = ch[pp];
ch[pp] = ch[pp + 1];
ch[pp + 1] = temp;
ss = String.valueOf(ch);
if (!vis.containsKey(ss)) {
if (ss.equals(f)) {
return dist + 1;
}
vis.put(ss, dist + 1);
q.add(new AbstractMap.SimpleEntry<String, Integer>(ss, pp + 1));
}
ch = ss.toCharArray();
temp = ch[pp];
ch[pp] = ch[pp + 1];
ch[pp + 1] = temp;
ss = String.valueOf(ch);
}
// if '_' can be swapped
// with the character 'i+2'
if (pp > 1 && ss.charAt(pp - 1) != ss.charAt(pp - 2)) {
char[] ch = ss.toCharArray();
char temp = ch[pp];
ch[pp] = ch[pp - 2];
ch[pp - 2] = temp;
ss = String.valueOf(ch);
if (!vis.containsKey(ss)) {
if (ss.equals(f)) {
return dist + 1;
}
vis.put(ss, dist + 1);
q.add(new AbstractMap.SimpleEntry<String, Integer>(ss, pp - 2));
}
ch = ss.toCharArray();
temp = ch[pp];
ch[pp] = ch[pp - 2];
ch[pp - 2] = temp;
ss = String.valueOf(ch);
}
// if '_' can be swapped
// with the character at 'i+2'
if (pp < n - 2 && ss.charAt(pp + 1) != ss.charAt(pp + 2)) {
char[] ch = ss.toCharArray();
char temp = ch[pp];
ch[pp] = ch[pp + 2];
ch[pp + 2] = temp;
ss = String.valueOf(ch);
if (!vis.containsKey(ss)) {
if (ss.equals(f)) {
return dist + 1;
}
vis.put(ss, dist + 1);
q.add(new AbstractMap.SimpleEntry<String, Integer>(ss, pp + 2));
}
ch = ss.toCharArray();
temp = ch[pp];
ch[pp] = ch[pp + 2];
ch[pp + 2] = temp;
ss = String.valueOf(ch);
}
}
return -1;
}
// Driver code
public static void main(String[] args)
{
String A = "aba_a";
String B = "_baaa";
System.out.println(minOperations(A, B));
}
}
Python3
# Python3 implementation of the approach
from collections import deque
# Function to return the minimum number of
# operations to convert string A to B
def minOperations(s: str, f: str) -> int:
# If both the strings are equal then
# no operation needs to be performed
if s == f:
return 0
vis = dict()
n = len(s)
pos = 0
for i in range(n):
if s[i] == '_':
# store the position of '_'
pos = i
break
# to store the generated string at every
# move and the position of '_' within it
q = deque()
q.append((s, pos))
# vis will store the minimum operations
# to reach that particular string
vis[s] = 0
while q:
ss = q[0][0]
pp = q[0][1]
# minimum moves to reach the string ss
dist = vis[ss]
q.popleft()
ss = list(ss)
# try all 4 possible operations
# if '_' can be swapped with
# the character on it's left
if pp > 0:
# swap with the left character
ss[pp], ss[pp - 1] = ss[pp - 1], ss[pp]
ss = ''.join(ss)
# if the string is generated
# for the first time
if ss not in vis:
# if generated string is
# the required string
if ss == f:
return dist + 1
# update the distance for the
# currently generated string
vis[ss] = dist + 1
q.append((ss, pp - 1))
ss = list(ss)
# restore the string before it was
# swapped to check other cases
ss[pp], ss[pp - 1] = ss[pp - 1], ss[pp]
ss = ''.join(ss)
# swap '_' with the character
# on it's right this time
if pp < n - 1:
ss = list(ss)
ss[pp], ss[pp + 1] = ss[pp + 1], ss[pp]
ss = ''.join(ss)
if ss not in vis:
if ss == f:
return dist + 1
vis[ss] = dist + 1
q.append((ss, pp + 1))
ss = list(ss)
ss[pp], ss[pp + 1] = ss[pp + 1], ss[pp]
ss = ''.join(ss)
# if '_' can be swapped
# with the character 'i+2'
if pp > 1 and ss[pp - 1] != ss[pp - 2]:
ss = list(ss)
ss[pp], ss[pp - 2] = ss[pp - 2], ss[pp]
ss = ''.join(ss)
if ss not in vis:
if ss == f:
return dist + 1
vis[ss] = dist + 1
q.append((ss, pp - 2))
ss = list(ss)
ss[pp], ss[pp - 2] = ss[pp - 2], ss[pp]
ss = ''.join(ss)
# if '_' can be swapped
# with the character at 'i+2'
if pp < n - 2 and ss[pp + 1] != ss[pp + 2]:
ss = list(ss)
ss[pp], ss[pp + 2] = ss[pp + 2], ss[pp]
ss = ''.join(ss)
if ss not in vis:
if ss == f:
return dist + 1
vis[ss] = dist + 1
q.append((ss, pp + 2))
ss = list(ss)
ss[pp], ss[pp + 2] = ss[pp + 2], ss[pp]
ss = ''.join(ss)
# Driver Code
if __name__ == "__main__":
A = "aba_a"
B = "_baaa"
print(minOperations(A, B))
# This code is contributed by
# sanjeev2552
JavaScript
// JavaScript implementation of the approach
// Function to return the minimum number of
// operations to convert string A to B
function minOperations(s, f) {
// If both the strings are equal then
// no operation needs to be performed
if (s === f) {
return 0;
}
let vis = {};
let n = s.length;
let pos = 0;
for (let i = 0; i < n; i++) {
if (s[i] === '_') {
// store the position of '_'
pos = i;
break;
}
}
// to store the generated string at every
// move and the position of '_' within it
let q = [];
q.push([s, pos]);
// vis will store the minimum operations
// to reach that particular string
vis[s] = 0;
while (q.length) {
let [ss, pp] = q[0];
// minimum moves to reach the string ss
let dist = vis[ss];
q.shift();
ss = ss.split('');
// try all 4 possible operations
// if '_' can be swapped with
// the character on it's left
if (pp > 0) {
// swap with the left character
[ss[pp], ss[pp - 1]] = [ss[pp - 1], ss[pp]];
ss = ss.join('');
// if the string is generated
// for the first time
if (!(ss in vis)) {
// if generated string is
// the required string
if (ss === f) {
return dist + 1;
}
// update the distance for the
// currently generated string
vis[ss] = dist + 1;
q.push([ss, pp - 1]);
}
ss = ss.split('');
// restore the string before it was
// swapped to check other cases
[ss[pp], ss[pp - 1]] = [ss[pp - 1], ss[pp]];
ss = ss.join('');
}
// swap '_' with the character
// on it's right this time
if (pp < n - 1) {
ss = ss.split('');
[ss[pp], ss[pp + 1]] = [ss[pp + 1], ss[pp]];
ss = ss.join('');
if (!(ss in vis)) {
if (ss === f) {
return dist + 1;
}
vis[ss] = dist + 1;
q.push([ss, pp + 1]);
}
ss = ss.split('');
[ss[pp], ss[pp + 1]] = [ss[pp + 1], ss[pp]];
ss = ss.join('');
}
// if '_' can be swapped
// with the character 'i+2'
if (pp > 1 && ss[pp - 1] !== ss[pp - 2]) {
ss = ss.split('');
[ss[pp], ss[pp - 2]] = [ss[pp - 2], ss[pp]];
ss = ss.join('');
if (!(ss in vis)) {
if (ss === f) {
return dist + 1;
}
vis[ss] = dist + 1;
q.push([ss, pp - 2]);
}
ss = ss.split('');
[ss[pp], ss[pp - 2]] = [ss[pp - 2], ss[pp]];
ss = ss.join('');
}
// if '_' can be swapped
// with the character at 'i+2'
if (pp < n - 2 && ss[pp + 1] !== ss[pp + 2]) {
ss = ss.split('');
[ss[pp], ss[pp + 2]] = [ss[pp + 2], ss[pp]];
ss = ss.join('');
if (!(ss in vis)) {
if (ss === f) {
return dist + 1;
}
vis[ss] = dist + 1;
q.push([ss, pp + 2]);
}
ss = ss.split('');
[ss[pp], ss[pp + 2]] = [ss[pp + 2], ss[pp]];
ss = ss.join('');
}
}
}
// Driver Code
let A = "aba_a";
let B = "_baaa";
console.log(minOperations(A, B))
// This code is contributed by codebraxnzt
C#
using System;
using System.Collections.Generic;
class GFG
{
// Function to return the minimum number of
// operations to convert string A to B
static int minOperations(string s, string f)
{
// If both the strings are equal then
// no operation needs to be performed
if (s == f)
return 0;
Dictionary<string, int> vis = new Dictionary<string, int>();
int n = s.Length;
int pos = 0;
for (int i = 0; i < s.Length; i++)
{
if (s[i] == '_')
{
// store the position of '_'
pos = i;
break;
}
}
// to store the generated string at every
// move and the position of '_' within it
Queue<Tuple<string, int>> q = new Queue<Tuple<string, int>>();
q.Enqueue(new Tuple<string, int>(s, pos));
// vis will store the minimum operations
// to reach that particular string
vis[s] = 0;
while (q.Count > 0)
{
string ss = q.Peek().Item1;
int pp = q.Peek().Item2;
// minimum moves to reach the string ss
int dist = vis[ss];
q.Dequeue();
// try all 4 possible operations
// if '_' can be swapped with
// the character on it's left
if (pp > 0)
{
// swap with the left character
char[] arr = ss.ToCharArray();
char temp = arr[pp];
arr[pp] = arr[pp - 1];
arr[pp - 1] = temp;
ss = new string(arr);
// if the string is generated
// for the first time
if (!vis.ContainsKey(ss))
{
// if generated string is
// the required string
if (ss == f)
return dist + 1;
// update the distance for the
// currently generated string
vis[ss] = dist + 1;
q.Enqueue(new Tuple<string, int>(ss, pp - 1));
}
// restore the string before it was
// swapped to check other cases
arr = ss.ToCharArray();
temp = arr[pp];
arr[pp] = arr[pp - 1];
arr[pp - 1] = temp;
ss = new string(arr);
}
// swap '_' with the character
// on it's right this time
if (pp < n - 1)
{
char[] arr = ss.ToCharArray();
char temp = arr[pp];
arr[pp] = arr[pp + 1];
arr[pp + 1] = temp;
ss = new string(arr);
if (!vis.ContainsKey(ss))
{
if (ss == f)
return dist + 1;
vis[ss] = dist + 1;
q.Enqueue(new Tuple<string, int>(ss, pp + 1));
}
arr = ss.ToCharArray();
temp = arr[pp];
arr[pp] = arr[pp + 1];
arr[pp + 1] = temp;
ss = new string(arr);
}
// if '_' can be swapped
// with the character 'i+2'
if (pp > 1 && ss[pp - 1] != ss[pp - 2]) {
char[] arr = ss.ToCharArray();
char temp = arr[pp];
arr[pp] = arr[pp - 2];
arr[pp - 2] = temp;
ss = new string(arr);
if (!vis.ContainsKey(ss)) {
if (ss == f) {
return dist + 1;
}
vis[ss] = dist + 1;
q.Enqueue(new Tuple<string, int>(ss, pp - 2));
}
arr = ss.ToCharArray();
temp = arr[pp];
arr[pp] = arr[pp - 2];
arr[pp - 2] = temp;
ss = new string(arr);
}
// if '_' can be swapped
// with the character at 'i+2'
if (pp < n - 2 && ss[pp + 1] != ss[pp + 2]) {
char[] arr = ss.ToCharArray();
char temp = arr[pp];
arr[pp] = arr[pp + 2];
arr[pp + 2] = temp;
ss = new string(arr);
if (!vis.ContainsKey(ss)) {
if (ss == f) {
return dist + 1;
}
vis[ss] = dist + 1;
q.Enqueue(new Tuple<string, int>(ss, pp + 2));
}
arr = ss.ToCharArray();
temp = arr[pp];
arr[pp] = arr[pp + 2];
arr[pp + 2] = temp;
ss = new string(arr);
}
}
return -1;
}
// Driver code
public static void Main()
{
string A = "aba_a";
string B = "_baaa";
Console.Write(minOperations(A, B));
}
}