Open In App

Minimize removal or insertions required to make two strings equal

Last Updated : 28 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given two strings S and T, both of length N and S is an anagram of string T, the task is to convert string S to T by performing the following operations minimum number of times:

  • Remove a character from either end.
  • Insert a character at any position.

Print the count of the minimum number of operations required.
 

Examples:

 

Input: S = “qpmon”, T = “mnopq”
Output: 3
Explanation: 
Operation 1: Remove ‘n’ from the end, and insert it at the second last position. The string S modifies to “qpmno”. 
Operation 2: Remove ‘q’ from the start, and insert it at the last position. The string S modifies to “pmnoq”. 
Operation 3: Remove ‘p’ from the start, and insert it at the second last position. The string S modifies to “mnopq” which is same as the desired string T.

Input: S = “abab”, T = “baba”
Output: 1

 

Approach: The given problem can be solved by the following observation: 

  • It is required to find the length of the longest substring of A which is a subsequence in B. Let the length of that sub string be L.
  • Then, the remaining characters can be inserted without disturbing the existing order.
  • To conclude, the optimal answer will be equal to N – L.

 Therefore, from the above observations, the minimum number of operations required is the difference between N and the length of the longest substring of the string A which is a subsequence in the string B

Below is the implementation of the above approach: 

C++




// C++ program for the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the longest substring
// in string A which is a subsequence in B
int findLongestSubstring(
    int posA, int posB, string& A,
    string& B, bool canSkip, int n,
    vector<vector<vector<int> > >& dp)
{
 
    // If the indices are out of bounds
    if (posA >= n || posB >= n) {
        return 0;
    }
 
    // If an already computed subproblem occurred
    if (dp[posA][posB][canSkip] != -1) {
        return dp[posA][posB][canSkip];
    }
 
    // Required answer if the all the
    // characters of A and B are the same
    int op1 = 0;
 
    // Required answer if there is no
    // substring A which is a
    //  subsequence in B
    int op2 = 0;
 
    // Required answer if the current
    // character in B is skipped
    int op3 = 0;
 
    if (A[posA] == B[posB]) {
        op1 = 1 + findLongestSubstring(
                      posA + 1, posB + 1, A,
                      B, 0, n, dp);
    }
    if (canSkip) {
        op2 = findLongestSubstring(
            posA + 1, posB, A, B,
            canSkip, n, dp);
    }
    op3 = findLongestSubstring(
        posA, posB + 1, A, B,
        canSkip, n, dp);
 
    // The answer for the subproblem is
    // the maximum among the three
    return dp[posA][posB][canSkip]
           = max(op1, max(op2, op3));
}
 
// Function to return the minimum strings
// operations required to make two strings equal
void minOperations(string A, string B, int N)
{
    // Initialize the dp vector
    vector<vector<vector<int> > > dp(
        N, vector<vector<int> >(
               N, vector<int>(2, -1)));
 
    cout << N - findLongestSubstring(
                    0, 0, A, B, 1, N, dp);
}
 
// Driver Code
int main()
{
    string A = "abab";
    string B = "baba";
 
    int N = A.size();
 
    minOperations(A, B, N);
 
    return 0;
}


Java




// Java program for the above approach
import java.io.*;
import java.util.*;
class GFG {
 
  // Function to find the longest substring
  // in string A which is a subsequence in B
  static int
    findLongestSubstring(int posA, int posB, String A,
                         String B, int canSkip, int n,
                         int dp[][][])
  {
 
    // If the indices are out of bounds
    if (posA >= n || posB >= n)
    {
      return 0;
    }
 
    // If an already computed subproblem occurred
    if (dp[posA][posB][canSkip] != -1)
    {
      return dp[posA][posB][canSkip];
    }
 
    // Required answer if the all the
    // characters of A and B are the same
    int op1 = 0;
 
    // Required answer if there is no
    // substring A which is a
    //  subsequence in B
    int op2 = 0;
 
    // Required answer if the current
    // character in B is skipped
    int op3 = 0;
    if (A.charAt(posA) == B.charAt(posB))
    {
      op1 = 1
        + findLongestSubstring(posA + 1, posB + 1,
                               A, B, 0, n, dp);
    }
    if (canSkip == 1) {
      op2 = findLongestSubstring(posA + 1, posB, A, B,
                                 canSkip, n, dp);
    }
    op3 = findLongestSubstring(posA, posB + 1, A, B,
                               canSkip, n, dp);
 
    // The answer for the subproblem is
    // the maximum among the three
    return dp[posA][posB][canSkip]
      = Math.max(op1, Math.max(op2, op3));
  }
 
  // Function to return the minimum strings
  // operations required to make two strings equal
  static void minOperations(String A, String B, int N)
  {
    // Initialize the dp vector
    int[][][] dp = new int[N][N][2];
 
    for(int i = 0; i < N; i++)
    {
      for(int j = 0; j < N; j++)
      {        
        for(int k = 0; k < 2; k++)
        {    
          dp[i][j][k] = -1;
        }
      }
    }
 
    System.out.println(
      N - findLongestSubstring(0, 0, A, B, 1, N, dp));
  }
 
  // Driver Code
  public static void main(String[] args)
  {
    String A = "abab";
    String B = "baba";
    int N = A.length();
    minOperations(A, B, N);
  }
}
 
// This code is contributed by Dharanendra L V


Python3




# Python3 program for the above approach
 
# Function to find the longest substring
# in A which is a subsequence in B
def findLongestSubstring(posA, posB, A, B, canSkip, n):
    global dp
    if (posA >= n or posB >= n):
        return 0
 
    # If an already computed subproblem occurred
    if (dp[posA][posB][canSkip] != -1):
        return dp[posA][posB][canSkip]
 
    # Required answer if the all the
    # characters of A and B are the same
    op1 = 0
 
    # Required answer if there is no
    # subA which is a
    # subsequence in B
    op2 = 0
 
    # Required answer if the current
    # character in B is skipped
    op3 = 0
 
    if (A[posA] == B[posB]):
        op1 = 1 + findLongestSubstring(posA + 1, posB + 1, A, B, 0, n)
    if (canSkip):
        op2 = findLongestSubstring(posA + 1, posB, A, B, canSkip, n)
 
    op3 = findLongestSubstring(posA, posB + 1, A, B, canSkip, n)
 
    # The answer for the subproblem is
    # the maximum among the three
    dp[posA][posB][canSkip] = max(op1, max(op2, op3))
    return dp[posA][posB][canSkip]
 
# Function to return the minimum strings
# operations required to make two strings equal
def minOperations(A, B, N):
    print(N - findLongestSubstring(0, 0, A, B, 1, N))
 
# Driver Code
if __name__ == '__main__':
    A = "abab"
    B = "baba"
    dp = [[[-1, -1] for i in range(len(A))] for i in range(len(A))]
    N = len(A)
    minOperations(A, B, N)
     
# This code is contributed by mohit kumar 29.


C#




// C# program for the above approach
using System;
class GFG
{
 
      // Function to find the longest substring
    // in string A which is a subsequence in B
    static int
    findLongestSubstring(int posA, int posB, String A,
                         String B, int canSkip, int n,
                         int[, , ] dp)
    {
 
        // If the indices are out of bounds
        if (posA >= n || posB >= n) {
            return 0;
        }
 
        // If an already computed subproblem occurred
        if (dp[posA, posB, canSkip] != -1) {
            return dp[posA, posB, canSkip];
        }
 
        // Required answer if the all the
        // characters of A and B are the same
        int op1 = 0;
 
        // Required answer if there is no
        // substring A which is a
        //  subsequence in B
        int op2 = 0;
 
        // Required answer if the current
        // character in B is skipped
        int op3 = 0;
 
        if (A[posA] == B[posB]) {
            op1 = 1
                  + findLongestSubstring(posA + 1, posB + 1,
                                         A, B, 0, n, dp);
        }
        if (canSkip == 1) {
            op2 = findLongestSubstring(posA + 1, posB, A, B,
                                       canSkip, n, dp);
        }
        op3 = findLongestSubstring(posA, posB + 1, A, B,
                                   canSkip, n, dp);
 
        // The answer for the subproblem is
        // the maximum among the three
        return dp[posA, posB, canSkip]
            = Math.Max(op1, Math.Max(op2, op3));
    }
 
    // Function to return the minimum strings
    // operations required to make two strings equal
    static void minOperations(String A, String B, int N)
    {
        // Initialize the dp vector
        int[, , ] dp = new int[N, N, 2];
           
          for(int i = 0; i < N; i++)
        {      
              for(int j = 0; j < N; j++)
            {               
                  for(int k = 0; k < 2; k++)
                {    
                      dp[i, j, k] = -1;
                }
            }
        }
        Console.WriteLine(
            N - findLongestSubstring(0, 0, A, B, 1, N, dp));
    }
 
    // Driver Code
    static public void Main ()
    {
        String A = "abab";
        String B = "baba";
        int N = A.Length;
        minOperations(A, B, N);
    }
}
 
// This code is contributed by Dharanendra L V


Javascript




<script>
 
// JavaScript program for the above approach
 
// Function to find the longest substring
// in string A which is a subsequence in B
function findLongestSubstring( posA, posB, A, B, canSkip, n, dp)
{
 
    // If the indices are out of bounds
    if (posA >= n || posB >= n) {
        return 0;
    }
 
    // If an already computed subproblem occurred
    if (dp[posA][posB][canSkip] != -1) {
        return dp[posA][posB][canSkip];
    }
 
    // Required answer if the all the
    // characters of A and B are the same
    var op1 = 0;
 
    // Required answer if there is no
    // substring A which is a
    //  subsequence in B
    var op2 = 0;
 
    // Required answer if the current
    // character in B is skipped
    var op3 = 0;
 
    if (A[posA] == B[posB]) {
        op1 = 1 + findLongestSubstring(
                      posA + 1, posB + 1, A,
                      B, 0, n, dp);
    }
    if (canSkip) {
        op2 = findLongestSubstring(
            posA + 1, posB, A, B,
            canSkip, n, dp);
    }
    op3 = findLongestSubstring(
        posA, posB + 1, A, B,
        canSkip, n, dp);
 
    // The answer for the subproblem is
    // the maximum among the three
    return dp[posA][posB][canSkip]
           = Math.max(op1, Math.max(op2, op3));
}
 
// Function to return the minimum strings
// operations required to make two strings equal
function minOperations(A, B, N)
{
    // Initialize the dp vector
    var dp = Array.from(Array(N), ()=> Array(N));
     
    for(var i =0; i<N; i++)
        for(var j =0; j<N; j++)
            dp[i][j] = new Array(2).fill(-1);
     
 
    document.write( N - findLongestSubstring(
                    0, 0, A, B, 1, N, dp));
}
 
// Driver Code
var A = "abab";
var B = "baba";
var N = A.length;
minOperations(A, B, N);
 
 
</script>


Output

1






Time Complexity: O(N2 )
Space Complexity: O(N2)

Efficient approach : Using DP Tabulation method ( Iterative approach )

The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memoization(top-down) because memoization method needs extra stack space of recursion calls.

Implementation :

C++




// C++ program to find the minimum
// operations required to make two
// strings equal
#include <bits/stdc++.h>
using namespace std;
 
// Function to return the minimum
// strings operations required to
// make two strings equal
void minOperations(string A, string B, int N)
{
    // Initialize the dp vector
    vector<vector<vector<int>>> dp(
        N + 1, vector<vector<int>>(
                   N + 1, vector<int>(2)));
 
    // Base case initialization
    for (int i = 0; i <= N; i++) {
        dp[i][0][0] = 0;
        dp[0][i][0] = 0;
        dp[i][0][1] = 0;
        dp[0][i][1] = 0;
    }
 
    // Update the dp table
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            if (A[i - 1] == B[j - 1]) {
                dp[i][j][0] = 1 + dp[i - 1][j - 1][0];
            }
            else {
                dp[i][j][0]
                    = max(dp[i - 1][j][0], dp[i][j - 1][0]);
            }
 
            dp[i][j][1]
                = max(dp[i - 1][j][1], dp[i][j - 1][1]);
 
            if (A[i - 1] == B[j - 1]) {
                dp[i][j][1] = max(dp[i][j][1],
                                   1 + dp[i - 1][j - 1][1]);
            }
        }
    }
 
    // Return the answer
    cout << N - max(dp[N][N][0], dp[N][N][1]);
}
 
// Driver code
int main()
{
    string A = "abab";
    string B = "baba";
 
    int N = A.size();
 
    minOperations(A, B, N);
 
    return 0;
}


Java




import java.util.Arrays;
 
public class GFG {
     
    // Function to return the minimum strings operations required to make two strings equal
    public static void minOperations(String A, String B, int N) {
        // Initialize the dp array
        int[][][] dp = new int[N + 1][N + 1][2];
 
        // Base case initialization
        for (int i = 0; i <= N; i++) {
            dp[i][0][0] = 0;
            dp[0][i][0] = 0;
            dp[i][0][1] = 0;
            dp[0][i][1] = 0;
        }
 
        // Update the dp table
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                if (A.charAt(i - 1) == B.charAt(j - 1)) {
                    dp[i][j][0] = 1 + dp[i - 1][j - 1][0];
                } else {
                    dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i][j - 1][0]);
                }
 
                dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i][j - 1][1]);
 
                if (A.charAt(i - 1) == B.charAt(j - 1)) {
                    dp[i][j][1] = Math.max(dp[i][j][1], 1 + dp[i - 1][j - 1][1]);
                }
            }
        }
 
        // Return the answer
        System.out.println(N - Math.max(dp[N][N][0], dp[N][N][1]));
    }
 
    // Driver code
    public static void main(String[] args) {
        String A = "abab";
        String B = "baba";
        int N = A.length();
        minOperations(A, B, N);
    }
}


Python3




# Python3 program to find the minimum
# operations required to make two
# strings equal
 
 
# Function to return the minimum
# strings operations required to
# make two strings equal
def min_operations(A, B, N):
    # Initialize the dp table
    dp = [[[0 for _ in range(2)] for _ in range(N + 1)] for _ in range(N + 1)]
 
    # Update the dp table
    for i in range(1, N + 1):
        for j in range(1, N + 1):
            if A[i - 1] == B[j - 1]:
                dp[i][j][0] = 1 + dp[i - 1][j - 1][0]
            else:
                dp[i][j][0] = max(dp[i - 1][j][0], dp[i][j - 1][0])
 
            dp[i][j][1] = max(dp[i - 1][j][1], dp[i][j - 1][1])
 
            if A[i - 1] == B[j - 1]:
                dp[i][j][1] = max(dp[i][j][1], 1 + dp[i - 1][j - 1][1])
 
    # Return the answer
    return N - max(dp[N][N][0], dp[N][N][1])
 
 
# Driver code
if __name__ == "__main__":
    A = "abab"
    B = "baba"
    N = len(A)
 
    result = min_operations(A, B, N)
    print(result)


C#




using System;
 
class GFG
{
    // Function to return the minimum strings operations required to make two strings equal
    static int MinOperations(string A, string B, int N)
    {
        // Initialize the dp array
        int[,,] dp = new int[N + 1, N + 1, 2];
 
        // Base case initialization
        for (int i = 0; i <= N; i++)
        {
            dp[i, 0, 0] = 0;
            dp[0, i, 0] = 0;
            dp[i, 0, 1] = 0;
            dp[0, i, 1] = 0;
        }
 
        // Update the dp table
        for (int i = 1; i <= N; i++)
        {
            for (int j = 1; j <= N; j++)
            {
                if (A[i - 1] == B[j - 1])
                {
                    dp[i, j, 0] = 1 + dp[i - 1, j - 1, 0];
                }
                else
                {
                    dp[i, j, 0] = Math.Max(dp[i - 1, j, 0], dp[i, j - 1, 0]);
                }
 
                dp[i, j, 1] = Math.Max(dp[i - 1, j, 1], dp[i, j - 1, 1]);
 
                if (A[i - 1] == B[j - 1])
                {
                    dp[i, j, 1] = Math.Max(dp[i, j, 1], 1 + dp[i - 1, j - 1, 1]);
                }
            }
        }
 
        // Return the answer
        return N - Math.Max(dp[N, N, 0], dp[N, N, 1]);
    }
 
    // Driver code
    static void Main()
    {
        string A = "abab";
        string B = "baba";
 
        int N = A.Length;
 
        int result = MinOperations(A, B, N);
 
        Console.WriteLine(result);
    }
}


Javascript




// Function to find the minimum operations required to make two strings equal
function minOperations(A, B, N) {
  // Initialize the 3D dp array
  let dp = new Array(N + 1);
  for (let i = 0; i < N + 1; i++) {
    dp[i] = new Array(N + 1);
    for (let j = 0; j < N + 1; j++) {
      dp[i][j] = [0, 0]; // Initialize as arrays to store two values
    }
  }
 
  // Base case initialization
  for (let i = 0; i <= N; i++) {
    dp[i][0][0] = 0;
    dp[0][i][0] = 0;
    dp[i][0][1] = 0;
    dp[0][i][1] = 0;
  }
 
  // Update the dp table
  for (let i = 1; i <= N; i++) {
    for (let j = 1; j <= N; j++) {
      if (A[i - 1] === B[j - 1]) {
        dp[i][j][0] = 1 + dp[i - 1][j - 1][0];
      } else {
        dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i][j - 1][0]);
      }
 
      dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i][j - 1][1]);
 
      if (A[i - 1] === B[j - 1]) {
        dp[i][j][1] = Math.max(dp[i][j][1], 1 + dp[i - 1][j - 1][1]);
      }
    }
  }
 
  // Return the answer
  return N - Math.max(dp[N][N][0], dp[N][N][1]);
}
 
// Driver code
let A = "abab";
let B = "baba";
 
let N = A.length;
 
let result = minOperations(A, B, N);
console.log(result);


Output

1






Time Complexity: O(N^2 )
Auxiliary Space: O(N^2)



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads