Find the string from an array that can be converted to a string S with minimum number of swaps
Last Updated :
04 Apr, 2023
Given a string S and an array of strings arr[] of length N and M respectively, the task is to find the string from the given array to the string S by swapping minimum number of characters . If no string can be converted to S, print -1.
Examples:
Input: S = "abc", arr[] = {"acb", "xyz"}
Output: acb
Explanation:
The string "acb" can be converted to "abc" by swapping 1 pair of characters "acb" -> "abc".
The string"xyz" cannot be converted to "abc".
Input: S = "abc", arr[] = {"ab", "xy", "cb"}
Output: -1
Approach: The problem can be solved by searching for anagrams of S from the given array of strings and then, for every such string, find the minimum number of character swaps required to convert the string to S.
Follow the steps below to solve the problem:
- Traverse the array of strings and for each string present in the array, check if it is an anagram of S or not.
- If no such string is found, then print -1.
- Otherwise, find the minimum number of swaps required to convert the current string into S, by iterating over the characters of the current string, say S1.
- Store the position of characters in S1 in 26 lists. For each character in S1, append its index to its corresponding list, i.e., list 0 stores all positions of the character 'a'. Similarly, list 1 stores all positions of 'b' and so on.
- After complete traversal of the string S1, iterate over the characters of the string S in reverse and for each character, say S[j], get its respective index from the given array of lists, say temp.
- Now, the optimal move is to move the character at the last index in temp to the index j. This is optimal because:
- Characters are being moved in every move. Hence, no move is being wasted.
- The last index in temp would be closer to j than other indices as the string is being iterated in reverse.
- To optimize, a Fenwick tree can be used to determine the modified positions of characters in S1, in case of any swaps.
Illustration:
Suppose, S = "abca", S1 = "cbaa"
Below is the list generated for S1:
List for 'a' = {2, 3}
List for 'b' = {1}
List for 'c' = {0}
Iterate over the characters of S, in reverse, by initializing minMoves with 0.
- S = "abca", i = 3
Remove last index from list corresponding to 'a', i.e. 3.
Search the Fenwick Tree to check if there are any indices to the left of this index in the Fenwick Tree or not.
Since the tree is empty now, no need to shift this index.
Add index 3 to the Fenwick Tree.
minMoves += (i - index) = (3 - 3). Therefore, minMoves = 0 - S = "abca", i = 2
Remove the last index from list corresponding to 'c', i.e. 0.
Search the Fenwick Tree to check if there are any indices to the left of this index in the Fenwick Tree or not.
Since the only index in the tree is 3, and it is to the right of 0, no need to shift this index.
Add index 0 to the Fenwick Tree.
minMoves += (i - index) = (2 - 0). Therefore, minMoves = 2 - S = "abca", i = 1
Remove last index from list corresponding to 'b', i.e. 1.
Search the Fenwick Tree to check if there are any indices to the left of this index in the Fenwick Tree or not.
The count obtained is 1, i.e. there was one character to the left of index 1, which is now, towards it's right.
Add index 1 to the Fenwick Tree.
new index = 1 - leftShit = 1 - 1 = 0
minMoves += (i - new index) = 1 - 0 = 3 - S = "abca", i= 0
Remove last index from list corresponding to 'a', i.e. 2.
Search the Fenwick Tree to check if there are any indices to the left of this index in the Fenwick tree or not.
The count obtained is 2, i.e. there were two characters to the left of index 2, which is now, towards its right.
Add index 2 to the Fenwick Tree.
new index = 2 - leftShit = 2 - 2 = 0
minMoves+= (i-new index) = 0 - 0 = 3
Below is the implementation of the above approach:
C++
// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
// Function to check is two
// strings are anagrams
bool checkIsAnagram(vector<int> charCountS,
vector<int> charCountS1)
{
for (int i = 0; i < 26; i++) {
if (charCountS[i] != charCountS1[i])
return false;
}
return true;
}
// Function to return the frequency of
// characters in the array of strings
vector<int> getCharCount(string S)
{
vector<int> charCount(26, 0);
for (char i : S)
charCount[i - 'a']++;
return charCount;
}
// Function to return the count of
// indices to the left of this index
int get(vector<int>& fenwickTree, int index)
{
int leftShift = 0;
leftShift += fenwickTree[index];
while (index > 0) {
index -= (-index) & index;
leftShift += fenwickTree[index];
}
return leftShift;
}
// Update function of Fenwick Tree
void update(vector<int>& fenwickTree, int index)
{
while (index < fenwickTree.size()) {
fenwickTree[index]++;
index += (-index) & index;
}
}
// Function to get all positions of
// characters present in the string S1
vector<vector<int> > getPositions(string S)
{
//@SuppressWarnings("unchecked")
vector<vector<int> > charPositions(26);
for (int i = 0; i < S.size(); i++)
charPositions[i - 'a'].push_back(i);
return charPositions;
}
// Function to return the minimum number
// of swaps required to convert S1 to S
int findMinMoves(string S, string S1)
{
// cout<<"run\n";
// Stores number of swaps
int minMoves = 0;
// Initialize Fenwick Tree
vector<int> fenwickTree(S.size() + 1);
// Get all positions of characters
// present in the string S1
vector<int> charPositions[26];
int j = 0;
for (char i : S1) {
charPositions[i - 'a'].push_back(j);
j++;
}
// cout<<charPositions[2].size()<<endl;
// Traverse the given string in reverse
for (int i = S.size() - 1; i >= 0; i--) {
// Get the list corresponding
// to character S[i]
vector<int> temp = charPositions[S[i] - 'a'];
// Size of the list
int size = temp.size() - 1;
// Get and remove last
// indices from the list
int index = temp[size] + 1;
charPositions[S[i] - 'a'].pop_back();
// temp.pop_back();
// Count of indices to
// the left of this index
int leftShift = get(fenwickTree, index);
// Update Fenwick T ree
update(fenwickTree, index);
// Shift the index to it's left
index -= leftShift;
// Update moves
minMoves += abs(i - index + 1);
}
// Return moves
return minMoves;
}
// Function to find anagram of S
// requiring minimum number of swaps
string getBeststring(string S, vector<string> group)
{
// Initialize variables
bool isAnagram = false;
string beststring = "";
int minMoves = INT_MAX;
// Count frequency of characters in S
vector<int> charCountS = getCharCount(S);
// Traverse the array of strings
for (string S1 : group) {
// Count frequency of characters in S1
vector<int> charCountS1 = getCharCount(S1);
// cout<<S1<<endl;
// Check if S1 is anagram of S
bool anagram
= checkIsAnagram(charCountS, charCountS1);
// cout<<anagram<<endl;
// If not an anagram of S
if (anagram == 0)
continue;
isAnagram = true;
// Count swaps required
// to convert S to S1
int moves = findMinMoves(S, S1);
// cout<<moves<<endl;
// Count minimum number of swaps
if (moves < minMoves) {
minMoves = moves;
beststring = S1;
}
}
// If no anagram is found, print -1
return (isAnagram) ? beststring : "-1";
}
// Driver Code
int main()
{
// Given string
string S = "abcdac";
// Given array of strings
vector<string> arr = { "cbdaca", "abcacd", "abcdef" };
string beststring = getBeststring(S, arr);
// Print answer
cout << (beststring) << endl;
}
// This code is contributed by mohit kumar 29
Java
// Java program for the above approach
import java.io.*;
import java.util.*;
class GFG {
// Function to find anagram of S
// requiring minimum number of swaps
static String getBestString(String S,
List<String> group)
{
// Initialize variables
boolean isAnagram = false;
String bestString = null;
int minMoves = Integer.MAX_VALUE;
// Count frequency of characters in S
int[] charCountS = getCharCount(S);
// Traverse the array of strings
for (String S1 : group) {
// Count frequency of characters in S1
int[] charCountS1 = getCharCount(S1);
// Check if S1 is anagram of S
boolean anagram
= checkIsAnagram(charCountS, charCountS1);
// If not an anagram of S
if (!anagram)
continue;
isAnagram = true;
// Count swaps required
// to convert S to S1
int moves = findMinMoves(S, S1);
// Count minimum number of swaps
if (moves < minMoves) {
minMoves = moves;
bestString = S1;
}
}
// If no anagram is found, print -1
return (isAnagram) ? bestString : "-1";
}
// Function to return the minimum number
// of swaps required to convert S1 to S
static int findMinMoves(String S, String S1)
{
// Stores number of swaps
int minMoves = 0;
// Initialize Fenwick Tree
int[] fenwickTree = new int[S.length() + 1];
// Get all positions of characters
// present in the string S1
List<List<Integer> > charPositions
= getPositions(S1);
// Traverse the given string in reverse
for (int i = S.length() - 1; i >= 0; i--) {
// Get the list corresponding
// to character S[i]
List<Integer> temp
= charPositions.get(S.charAt(i) - 'a');
// Size of the list
int size = temp.size() - 1;
// Get and remove last
// indices from the list
int index = temp.remove(size) + 1;
// Count of indices to
// the left of this index
int leftShift = get(fenwickTree, index);
// Update Fenwick T ree
update(fenwickTree, index);
// Shift the index to it's left
index -= leftShift;
// Update moves
minMoves += Math.abs(i - index + 1);
}
// Return moves
return minMoves;
}
// Function to get all positions of
// characters present in the string S1
static List<List<Integer> > getPositions(String S)
{
@SuppressWarnings("unchecked")
List<List<Integer> > charPositions
= new ArrayList();
for (int i = 0; i < 26; i++)
charPositions.add(new ArrayList<Integer>());
for (int i = 0; i < S.length(); i++)
charPositions.get(S.charAt(i) - 'a').add(i);
return charPositions;
}
// Update function of Fenwick Tree
static void update(int[] fenwickTree, int index)
{
while (index < fenwickTree.length) {
fenwickTree[index]++;
index += (-index) & index;
}
}
// Function to return the count of
// indices to the left of this index
static int get(int[] fenwickTree, int index)
{
int leftShift = 0;
leftShift += fenwickTree[index];
while (index > 0) {
index -= (-index) & index;
leftShift += fenwickTree[index];
}
return leftShift;
}
// Function to return the frequency of
// characters in the array of strings
static int[] getCharCount(String S)
{
int[] charCount = new int[26];
for (int i = 0; i < S.length(); i++)
charCount[S.charAt(i) - 'a']++;
return charCount;
}
// Function to check is two
// strings are anagrams
static boolean checkIsAnagram(int[] charCountS,
int[] charCountS1)
{
for (int i = 0; i < 26; i++) {
if (charCountS[i] != charCountS1[i])
return false;
}
return true;
}
// Driver Code
public static void main(String[] args)
{
// Given string
String S = "abcdac";
// Given array of strings
String arr[] = { "cbdaca", "abcacd", "abcdef" };
String bestString
= getBestString(S, Arrays.asList(arr));
// Print answer
System.out.println(bestString);
}
}
Python3
# Python program for the above approach
import math
# Function to check is two
# strings are anagrams
def checkIsAnagram(charCountS, charCountS1):
for i in range(26):
if charCountS[i] != charCountS1[i]:
return False
return True
# Function to return the frequency of
# characters in the array of strings
def getCharCount(S):
charCount = [0] * 26
for i in S:
charCount[ord(i) - ord('a')] += 1
return charCount
# Function to return the count of
# indices to the left of this index
def get(fenwickTree, index):
leftShift = 0
leftShift += fenwickTree[index]
while index > 0:
index -= (-index) & index
leftShift += fenwickTree[index]
return leftShift
# Update function of Fenwick Tree
def update(fenwickTree, index):
while index < len(fenwickTree):
fenwickTree[index] += 1
index += (-index) & index
# Function to get all positions of
# characters present in the string S1
def getPositions(S):
charPositions = [[] for _ in range(26)]
for i in range(len(S)):
charPositions[ord(S[i]) - ord('a')].append(i)
return charPositions
# Function to return the minimum number
# of swaps required to convert S1 to S
def findMinMoves(S, S1):
# Stores number of swaps
minMoves = 0
# Initialize Fenwick Tree
fenwickTree = [0] * (len(S) + 1)
charPositions = [[] for _ in range(26)]
j = 0
for i in S1:
charPositions[ord(i) - ord('a')].append(j)
j += 1
for i in range(len(S) - 1, -1, -1):
temp = charPositions[ord(S[i]) - ord('a')]
size = len(temp) - 1
index = temp[size] + 1
charPositions[ord(S[i]) - ord('a')].pop()
leftShift = get(fenwickTree, index)
update(fenwickTree, index)
index -= leftShift
minMoves += abs(i - index + 1)
return minMoves
# Function to find anagram of S
# requiring minimum number of swaps
def getBeststring(S, group):
isAnagram = False
beststring = ""
minMoves = math.inf
# Count frequency of characters in S
charCountS = getCharCount(S)
for S1 in group:
# Count frequency of characters in S1
charCountS1 = getCharCount(S1)
# Check if S1 is anagram of S
anagram = checkIsAnagram(charCountS, charCountS1)
if not anagram:
continue
isAnagram = True
# Count swaps required
# to convert S to S1
moves = findMinMoves(S, S1)
# Count minimum number of swaps
if moves < minMoves:
minMoves = moves
beststring = S1
# If no anagram is found, print -1
return beststring if isAnagram else "-1"
# Driver Code
# Give String
S = "abcdac"
# Given array of strings
arr = ["cbdaca", "abcacd", "abcdef"]
beststring = getBeststring(S, arr)
print(beststring)
# This code is contributed by adityashae15
JavaScript
// Javascript equivalent
// Function to check is two
// strings are anagrams
function checkIsAnagram(charCountS, charCountS1) {
for (let i = 0; i < 26; i++) {
if (charCountS[i] !== charCountS1[i]) {
return false;
}
}
return true;
}
// Function to return the frequency of
// characters in the array of strings
function getCharCount(S) {
let charCount = new Array(26).fill(0);
for (let i = 0; i < S.length; i++) {
charCount[S.charCodeAt(i) - 'a'.charCodeAt()]++;
}
return charCount;
}
// Function to return the count of
// indices to the left of this index
function get(fenwickTree, index) {
let leftShift = 0;
leftShift += fenwickTree[index];
while (index > 0) {
index -= (-index) & index;
leftShift += fenwickTree[index];
}
return leftShift;
}
// Update function of Fenwick Tree
function update(fenwickTree, index) {
while (index < fenwickTree.length) {
fenwickTree[index]++;
index += (-index) & index;
}
}
// Function to get all positions of
// characters present in the string S1
function getPositions(S) {
let charPositions = [];
for (let i = 0; i < 26; i++) {
charPositions.push([]);
}
for (let i = 0; i < S.length; i++) {
charPositions[S.charCodeAt(i) - 'a'.charCodeAt()].push(i);
}
return charPositions;
}
// Function to return the minimum number
// of swaps required to convert S1 to S
function findMinMoves(S, S1) {
// Stores number of swaps
let minMoves = 0;
// Initialize Fenwick Tree
let fenwickTree = new Array(S.length + 1).fill(0);
let charPositions = [];
for (let i = 0; i < 26; i++) {
charPositions.push([]);
}
let j = 0;
for (let i = 0; i < S1.length; i++) {
charPositions[S1.charCodeAt(i) - 'a'.charCodeAt()].push(j);
j++;
}
for (let i = S.length - 1; i >= 0; i--) {
let temp = charPositions[S.charCodeAt(i) - 'a'.charCodeAt()];
let size = temp.length - 1;
let index = temp[size] + 1;
charPositions[S.charCodeAt(i) - 'a'.charCodeAt()].pop();
let leftShift = get(fenwickTree, index);
update(fenwickTree, index);
index -= leftShift;
minMoves += Math.abs(i - index + 1);
}
return minMoves;
}
// Function to find anagram of S
// requiring minimum number of swaps
function getBeststring(S, group) {
let isAnagram = false;
let beststring = "";
let minMoves = Number.MAX_VALUE;
// Count frequency of characters in S
let charCountS = getCharCount(S);
for (let S1 of group) {
// Count frequency of characters in S1
let charCountS1 = getCharCount(S1);
// Check if S1 is anagram of S
let anagram = checkIsAnagram(charCountS, charCountS1);
if (!anagram) {
continue;
}
isAnagram = true;
// Count swaps required
// to convert S to S1
let moves = findMinMoves(S, S1);
// Count minimum number of swaps
if (moves < minMoves) {
minMoves = moves;
beststring = S1;
}
}
// If no anagram is found, print -1
return isAnagram ? beststring : "-1";
}
// Driver Code
// Give String
let S = "abcdac";
// Given array of strings
let arr = ["cbdaca", "abcacd", "abcdef"];
let beststring = getBeststring(S, arr);
console.log(beststring);
C#
// C# program for the above approach
using System;
using System.Collections.Generic;
public class AnagramSwaps {
// Function to check if two
// strings are anagrams
public static bool CheckIsAnagram(int[] charCountS,
int[] charCountS1)
{
for (int i = 0; i < 26; i++) {
if (charCountS[i] != charCountS1[i]) {
return false;
}
}
return true;
}
// Function to return the frequency of
// characters in the array of strings
public static int[] GetCharCount(string S)
{
int[] charCount = new int[26];
foreach(char c in S) { charCount[c - 'a']++; }
return charCount;
}
// Function to return the count of
// indices to the left of this index
public static int Get(int[] fenwickTree, int index)
{
int leftShift = 0;
leftShift += fenwickTree[index];
while (index > 0) {
index -= (-index) & index;
leftShift += fenwickTree[index];
}
return leftShift;
}
// Update function of Fenwick Tree
public static void Update(int[] fenwickTree, int index)
{
while (index < fenwickTree.Length) {
fenwickTree[index] += 1;
index += (-index) & index;
}
}
// Function to get all positions of
// characters present in the string S1
public static List<int>[] GetPositions(string S)
{
List<int>[] charPositions = new List<int>[ 26 ];
for (int i = 0; i < 26; i++) {
charPositions[i] = new List<int>();
}
for (int i = 0; i < S.Length; i++) {
charPositions[S[i] - 'a'].Add(i);
}
return charPositions;
}
// Function to return the minimum number
// of swaps required to convert S1 to S
public static int FindMinMoves(string S, string S1)
{
// Stores number of swaps
int minMoves = 0;
// Initialize Fenwick Tree
int[] fenwickTree = new int[S.Length + 1];
List<int>[] charPositions = new List<int>[ 26 ];
for (int i = 0; i < 26; i++) {
charPositions[i] = new List<int>();
}
int j = 0;
foreach(char c in S1)
{
charPositions[c - 'a'].Add(j);
j++;
}
for (int i = S.Length - 1; i >= 0; i--) {
List<int> temp = charPositions[S[i] - 'a'];
int size = temp.Count - 1;
int index = temp[size] + 1;
charPositions[S[i] - 'a'].RemoveAt(size);
int leftShift = Get(fenwickTree, index);
Update(fenwickTree, index);
index -= leftShift;
minMoves += Math.Abs(i - index + 1);
}
return minMoves;
}
// Function to find anagram of S
// requiring minimum number of swaps
public static string GetBestString(string S,
string[] group)
{
bool isAnagram = false;
string bestString = "";
int minMoves = int.MaxValue;
// Count frequency of characters in S
int[] charCountS = GetCharCount(S);
foreach(string S1 in group)
{
// Count frequency of characters in S1
int[] charCountS1 = GetCharCount(S1);
// Check if S1 is anagram of S
bool anagram
= CheckIsAnagram(charCountS, charCountS1);
if (!anagram)
continue;
isAnagram = true;
// Count swaps required to convert S to S1
int moves = FindMinMoves(S, S1);
// Count minimum number of swaps
if (moves < minMoves) {
minMoves = moves;
bestString = S1;
}
}
// If no anagram is found, return -1
return isAnagram ? bestString : "-1";
}
// Driver Code
static void Main(string[] args)
{
// Give String
string S = "abcdac";
// Given array of strings
string[] arr = { "cbdaca", "abcacd", "abcdef" };
string bestString = GetBestString(S, arr);
Console.WriteLine(bestString);
}
}
Time Complexity: O(M * N * logN)
Auxiliary Space: O(N)
Similar Reads
Find the number of ways to form a string of length N that can be rearranged to include S as a substring.
Given an integer N and string S of size M, the task is to find the number of ways of forming string of length N such that it is possible to rearrange the string to have S as substring. Print the answer modulo 109 + 7. Note: All characters of string S are distinct. Examples: Input: N = 3, S = "abc"Ou
8 min read
Minimum number of adjacent swaps to convert a string into its given anagram
Given two strings s1 and s2, the task is to find the minimum number of steps required to convert s1 into s2. The only operation allowed is to swap adjacent elements in the first string. Every swap is counted as a single step.Examples: Input: s1 = "abcd", s2 = "cdab" Output: 4 Swap 2nd and 3rd elemen
8 min read
Minimum number of given operations required to convert a string to another string
Given two strings S and T of equal length. Both strings contain only the characters '0' and '1'. The task is to find the minimum number of operations to convert string S to T. There are 2 types of operations allowed on string S: Swap any two characters of the string.Replace a '0' with a '1' or vice
14 min read
Minimize the number of replacements to get a string with same number of 'a', 'b' and 'c' in it
Given a string consisting of only three possible characters 'a', 'b' or 'c'. The task is to replace characters of the given string with 'a', 'b' or 'c' only such that there is the equal number of characters of 'a', 'b' and 'c' in the string. The task is to minimize the number of replacements and pri
15 min read
Make all strings from a given array equal by replacing minimum number of characters
Given an array of equal-length strings arr[], the task is to make all the strings of the array equal by replacing any character of a string with any other character, minimum number of times. Examples: Input: arr[] = { "west", "east", "wait" } Output: 3 Explanation: Replacing arr[0][1] with 'a' modif
8 min read
Find all substrings that are anagrams of another substring of the string S
Given a string S, the task is to find all the substrings in the string S which is an anagram of another different substring in the string S. The different substrings mean the substring starts at a different index. Examples: Input: S = "aba"Output: a a ab baExplanation:Following substrings are anagra
6 min read
Convert string X to an anagram of string Y with minimum replacements
Given two strings X and Y, we need to convert string X into an anagram of string Y with minimum replacements. If we have multiple ways of achieving the target, we go for the lexicographically smaller string where the length of each string \in [1, 100000] Examples: Input : X = "CDBABC" Y = "ADCABD" O
13 min read
Count of strings in Array A that can be made equal to strings in Array B by appending characters
Given two arrays of strings SearchWord[] and FindWord[]. The task is to check how many strings in FindWord[] can be formed after the following operations on as many strings as possible: Pick a string from SearchWord[].Add one English alphabet (that is not present in that string).Rearrange the string
13 min read
Minimum number of flips or swaps of adjacent characters required to make two strings equal
Given two binary strings A and B of length N, the task is to count the minimum number of operations required to make the two given strings equal by either swapping adjacent characters or flipping any character of the string A. Examples: Input: A = "100", B = "001"Output: 2Explanation: Flipping chara
12 min read
Print all strings in the given array that occur as the substring in the given string
Given an array of string arr[] and a string str, the task is to print all the strings in arr[] that occur as a substring in str. Example: Input: str ="geeksforgeeks", arr[] ={ "forg", "geek", "ek", "dog", "sfor"}Output: forggeekeksforExplanation: The strings "forg", "geek", "ek" and "sfor" occur as
5 min read