Transform String to Another using Minimum Operations

Last Updated : 30 Apr, 2026

Given two strings s1 and s2. Find the minimum number of steps required to transform string s1 into string s2. The only allowed operation for the transformation is selecting a character from string s1 and inserting it in the beginning of string s2.

Examples: 

Input: s1 = "abd", s2 = "bad"
Output: 1
Explanation: The conversion can take place in 1 operation: Pick 'b' and place it at the front.

Input: s1 = "GeeksForGeeks" s2 = "ForGeeksGeeks"
Output: 3
Explanation: The conversion can take place in 3 operations:
Pick 'r' and place it at the front, A = "rGeeksFoGeeks"
Pick 'o' and place it at the front, A = "orGeeksFGeeks"
Pick 'F' and place it at the front, A = "ForGeeksGeeks"

Try It Yourself
redirect icon

Using Hash Map (or Dictionary) and Two Pointers - O(n) Time

The transformation is only possible if both strings have the same characters with the exact same frequencies. use a HashMap (or a frequency array) to count the characters in string s1 and then "cancel them out" using string s2.

If frequencies are same, then begin matching from end of both strings.

  • Keep moving both pointers while there is a match
  • For mismatches, increment result and move only pointer of s1 as the current substring of s1 can match with current prefix of s2.
C++
#include <iostream>
#include <string>
#include <unordered_map>

using namespace std;

int transform(string &s1, string &s2) {
    
    if (s1.length() != s2.length()) {
        return -1;
    }

    // Create a map to store the frequency of characters in string s1
    unordered_map<char, int> m;
    int n = s1.length();
    for (int i = 0; i < n; i++) {
        
        // If the character already exists in the map
        if (m.count(s1[i])) 
            m[s1[i]]++;
            
        // Add the character to the map with a frequency of 1
        else
            m[s1[i]] = 1;
    }

    // Subtract the frequency of characters in string s2 from the map
    for (int i = 0; i < n; i++) {
        if (m.count(s2[i]))
            m[s2[i]]--;
    }

    // Check if all frequencies are 0 to verify strings are anagrams
    for (auto it : m) {
        if (it.second != 0) 
            return -1;
    }

    // Calculate minimum operations using a greedy right-to-left approach
    int i = n - 1, j = n - 1;
    int res = 0;
    while (i >= 0 && j >= 0) {
        
        // If characters mismatch, s1[i] must be moved to the front
        while (i >= 0 && s1[i] != s2[j]) {
        
            // Increment the number of operations required
            res++;
        
            // Move pointer i to the left to find a match for s2[j]
            i--;
        }
        
        // Move both pointers if a match is found or i is exhausted
        i--;
        j--;
    }
    
    return res;
}

int main() {
    string s1 = "GeeksForGeeks";
    string s2 = "ForGeeksGeeks";

    cout << transform(s1, s2) << endl;
    
    return 0;
}
Java
import java.util.HashMap;
import java.util.Map;

class GFG {
    public static int transform(String s1, String s2) {
        
        // If lengths differ, transformation is impossible
        if (s1.length() != s2.length()) {
            return -1;
        }

        // Step 1: Character Frequency Check (Anagram Check)
        // We use a HashMap to ensure both strings contain the exact same characters.
        HashMap<Character, Integer> m = new HashMap<Character, Integer>();
        int n = s1.length();
        
        // Count characters in string s1
        for (int i = 0; i < n; i++) {
            m.put(s1.charAt(i), m.getOrDefault(s1.charAt(i), 0) + 1);
        }

        // Subtract character counts based on string s2
        for (int i = 0; i < n; i++) {
            if (m.containsKey(s2.charAt(i)))
                m.put(s2.charAt(i), m.get(s2.charAt(i)) - 1);
        }

        // If any count is non-zero, strings aren't anagrams; return -1
        for (Map.Entry<Character, Integer> entry : m.entrySet()) {
            if (entry.getValue() != 0)
                return -1;
        }

        // Step 2: Greedy Two-Pointer Approach
        // Since we can only move to the FRONT, we match characters starting from the BACK (right to left).
        int i = n - 1, j = n - 1;
        int res = 0;
        
        while (i >= 0 && j >= 0) {
            // If characters at current pointers don't match, s1.charAt(i) 
            // is a character that must be moved to the front eventually.
            while (i >= 0 && s1.charAt(i) != s2.charAt(j)) {
                res++; // This character 'i' will be moved, increment operations
                i--;   // Move 'i' left to find the next potential match for s2[j]
            }
            
            // If we found a match (s1[i] == s2[j]), move both pointers left to check the next set
            if (i >= 0) {
                i--;
                j--;
            }
        }
        return res;
    }

    public static void main(String[] args) {
        String s1 = "GeeksForGeeks";
        String s2 = "ForGeeksGeeks";

        System.out.println(transform(s1, s2));
    }
}
Python
def transform(s1, s2):
    if len(s1) != len(s2):
        return -1
    
    # Step 1: Anagram Check using a frequency dictionary
    m = {}
    n = len(s1)
    
    # Count frequencies in string s1
    for i in range(n):
        if s1[i] in m:
            m[s1[i]] += 1
        else:
            m[s1[i]] = 1
    
    # Subtract frequencies based on string s2
    for i in range(n):
        if s2[i] in m:
            m[s2[i]] -= 1
        else:
            # If a character in s2 isn't in s1 at all
            return -1
    
    # If any frequency is not zero, the strings cannot be transformed
    for key in m:
        if m[key] != 0:
            return -1
    
    # Step 2: Greedy Two-Pointer Approach
    # We move from right to left to find characters already in their target positions
    i, j = n - 1, n - 1
    res = 0
    
    while i >= 0 and j >= 0:
        # If s1[i] doesn't match s2[j], it must be moved to the front eventually
        while i >= 0 and s1[i] != s2[j]:
            res += 1
            # Move i to the left to check the next available character
            i -= 1
        
        # If s1[i] matches s2[j], we move both pointers left to find the next match
        i -= 1
        j -= 1
    
    return res

if __name__ == "__main__":
    
    s1 = "GeeksForGeeks"
    s2 = "ForGeeksGeeks"

    print(transform(s1, s2))
C#
using System;
using System.Collections.Generic;

class GFG {
    public static int transform(string s1, string s2) {
        
        // First, check if the transformation is even possible based on length
        if (s1.Length != s2.Length) {
            return -1;
        }

        // Use a dictionary to track character frequencies for an anagram check
        Dictionary<char, int> m = new Dictionary<char, int>();
        int n = s1.Length;
        
        // Count each character in string s1
        for (int i = 0; i < n; i++) {
            if (m.ContainsKey(s1[i])) {
                m[s1[i]]++;
            }
            else {
                m[s1[i]] = 1;
            }
        }

        // Subtract frequencies based on string s2
        for (int i = 0; i < n; i++) {
            if (m.ContainsKey(s2[i])) {
                m[s2[i]]--;
            }
            else {
                // If a character in s2 doesn't exist in s1, they aren't anagrams
                return -1;
            }
        }

        // If any value is not zero, the strings have different character counts
        foreach (var entry in m) {
            if (entry.Value != 0) {
                return -1;
            }
        }

        // Two-pointer greedy approach starting from the end of the strings
        int it = n - 1, j = n - 1;
        int res = 0;

        while (it >= 0 && j >= 0) {
            
            // If characters don't match, s1[it] must be moved to the front
            while (it >= 0 && s1[it] != s2[j]) {
                res++;
                it--;
            }

            // If we found a match, move both pointers to the left
            if (it >= 0) {
                it--;
                j--;
            }
        }
        
        return res;
    }

    public static void Main(string[] args) {
        string s1 = "GeeksForGeeks";
        string s2 = "ForGeeksGeeks";

        Console.WriteLine(transform(s1, s2));
    }
}
JavaScript
function transform(s1, s2) {
    if (s1.length !== s2.length) {
        return -1;
    }

    // Step 1: Anagram Check using a frequency object
    const m = {};
    const n = s1.length;
    
    // Count frequencies in string s1
    for (let i = 0; i < n; i++) {
        if (m[s1[i]]) {
            m[s1[i]]++;
        } else {
            m[s1[i]] = 1;
        }
    }

    // Subtract frequencies based on string s2
    for (let i = 0; i < n; i++) {
        if (m[s2[i]]) {
            m[s2[i]]--;
        } else if (m[s2[i]] === undefined) {
            // Character in s2 does not exist in s1
            return -1;
        }
    }

    // If any frequency is not zero, the strings are not anagrams
    for (const char in m) {
        if (m[char] !== 0) {
            return -1;
        }
    }

    // Step 2: Greedy Two-Pointer Approach
    // We scan from right to left because we can only move to the front
    let i = n - 1;
    let j = n - 1;
    let res = 0;

    while (i >= 0 && j >= 0) {
        // If characters don't match, s1[i] is out of place and must move
        while (i >= 0 && s1[i] !== s2[j]) {
            res++;
            // Skip this character in s1 and count it as a "move to front"
            i--;
        }
        
        // If they match, move both pointers to check the next pair
        if (i >= 0) {
            i--;
            j--;
        }
    }
    
    return res;
}

// Driver code
const s1 = "GeeksForGeeks";
const s2 = "ForGeeksGeeks";

console.log(transform(s1, s2));

Output
3

Note : We can further optimize the above approach by using a count array of size 256 instead of map.

Comment