Skip to content
Related Articles

Related Articles

Minimum cost to delete characters from String A to remove any subsequence as String B

View Discussion
Improve Article
Save Article
  • Last Updated : 29 Apr, 2022

Given two strings A and B of size N and M respectively, where B is a sub-sequence of A and an array arr[] of size N, where arr[i] is the cost to delete ith character from string A. The task is to find the minimum cost to delete characters from A such that after deletion no subsequence of A is the same as B.

Examples:

Input: A = “abccd”, B = “ccd”, arr[] = {1, 2, 3, 4, 5}
Output: 3
Explanation: If we remove either ‘d’ or a single ‘c’ from A then it will not be possible to construct a sub-sequence equals to B. 
Among these the cost to remove the ‘c’ at index 2 is minimum that is 3. So the answer is 3.

Input: A = “abccdabccdabccd”, B = “bccd”, arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
Output: 21
Explanation: If we remove the three ‘b’s with cost 2, 7 and 5, then A becomes “accdaccdaccd”. 
Now there is no way to construct a sub-sequence = “bccd” 

 

Approach: The naive approach to solve the problem is to use recursion and to find a common subsequence between A and B as per the following idea:

If the character of A and B matches there will be 2 options: either remove that character from A or keep that character and remove other characters.

Follow the steps mentioned below to implement the idea:

  • Recursively traverse through string A using pointer i and keep a pointer j to point to B.
  • In each recursive function:
    • If the end of the string is reached return 0 if any character is removed (checked by a counter of deleted elements) otherwise return high positive value.
    • If A[i] = B[j] there are two choices:
      • Remove A[i] and add cost arr[i] to answer and recursively call for the next elements.
      • Keep A[i] and move forward.
    • Else keep moving forward until A[i] matches B[i].
    • Return the minimum cost among the above two cases from each recursive call.
  • Return the minimum cost as answer.

Time Complexity: O(2M)
Auxiliary Space: O(1)

Efficient Approach: The time of the above approach can be further optimized using Dynamic Programming as per the following idea:

Use a 3D dp[][][] array to store the minimum cost until a given position in A and B and for removing at least one character. dp[i][j][] stores minimum cost to delete characters till ith index of A and jth index of B where either at least one character is deleted or not. 
Hence the third dimension only has two value either 1 (at least one is deleted) or 0 (none is deleted)

Below is the implementation of the above approach.

C++




// C++ program for the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Array for memoization
int dp[101][101][2];
 
// Recursive function to calculate
// the minimum cost using dynamic programming
int minCostUtil(string& a, int n,
                string& b, int m,
                vector<int>& c, int removed)
{
 
    // Base case reached the end of string
    if (n == 0 || m == 0) {
 
        // Removed 0 characters
        // return high (+)ve value
        if (removed == 0)
            return 99999;
        return 0;
    }
 
    // Return pre-calculated value
    if (dp[n][m][removed > 0 ? 1 : 0] != -1)
        return dp[n][m][removed > 0 ? 1 : 0];
 
    // If characters match return the minimum of
    // 1. Removing the character from A and
    // adding the cost
    // 2. Moving forward to remove some other
    // character and decrease the counter as
    // this character will not be removed.
    if (a[n - 1] == b[m - 1]) {
        dp[n][m][removed > 0 ? 1 : 0]
            = min(c[n - 1]
                      + minCostUtil(a, n - 1,
                                    b, m, c, removed),
                  minCostUtil(a, n - 1, b, m - 1,
                              c, removed - 1));
        return dp[n][m][removed > 0 ? 1 : 0];
    }
 
    // If no match then move through string
    // A and try removing some other
    // character which matches, i.e can be
    // part of the subsequence that is equal to B
    else
        return dp[n][m][removed > 0 ? 1 : 0]
               = minCostUtil(a, n - 1,
                             b, m, c, removed);
}
 
// Function to calculate minimum cost
int minCost(string& a, string& b,
            vector<int>& c)
{
    memset(dp, -1, sizeof(dp));
    return minCostUtil(a, a.size(), b,
                       b.size(), c, b.size());
}
 
// Driver code
int main()
{
    string A = "abccdabccdabccd";
    string B = "bccd";
    vector<int> arr = { 1, 2, 3, 4, 5,
                        6, 7, 8, 9, 10,
                        11, 12, 13, 14, 15 };
 
    cout << minCost(A, B, arr);
    return 0;
}


Java




// Java program for the above approach
import java.util.*;
 
public class GFG {
 
  // Array for memoization
  static int dp[][][] = new int[101][101][2];
 
  // Recursive function to calculate
  // the minimum cost using dynamic programming
  static int minCostUtil(String a, int n, String b, int m,
                         int[] c, int removed)
  {
 
    // Base case reached the end of string
    if (n == 0 || m == 0) {
 
      // Removed 0 characters
      // return high (+)ve value
      if (removed == 0)
        return 99999;
      return 0;
    }
 
    // Return pre-calculated value
    if (dp[n][m][removed > 0 ? 1 : 0] != -1)
      return dp[n][m][removed > 0 ? 1 : 0];
 
    // If characters match return the minimum of
    // 1. Removing the character from A and
    // adding the cost
    // 2. Moving forward to remove some other
    // character and decrease the counter as
    // this character will not be removed.
    if (a.charAt(n - 1) == b.charAt(m - 1)) {
      dp[n][m][removed > 0 ? 1 : 0]
        = Math.min(c[n - 1]
                   + minCostUtil(a, n - 1, b, m,
                                 c, removed),
                   minCostUtil(a, n - 1, b, m - 1,
                               c, removed - 1));
      return dp[n][m][removed > 0 ? 1 : 0];
    }
 
    // If no match then move through string
    // A and try removing some other
    // character which matches, i.e can be
    // part of the subsequence that is equal to B
    else
      return dp[n][m][removed > 0 ? 1 : 0]
      = minCostUtil(a, n - 1, b, m, c, removed);
  }
 
  // Function to calculate minimum cost
  static int minCost(String a, String b, int[] c)
  {
    for (int i = 0; i < 101; i++) {
      for (int j = 0; j < 101; j++) {
        for (int k = 0; k < 2; k++) {
          dp[i][j][k] = -1;
        }
      }
    }
    return minCostUtil(a, a.length(), b, b.length(), c,
                       b.length());
  }
 
  // Driver code
  public static void main(String args[])
  {
    String A = "abccdabccdabccd";
    String B = "bccd";
    int[] arr = { 1, 234567, 8,
                 9, 10, 11, 12, 13, 14, 15 };
 
    System.out.print(minCost(A, B, arr));
  }
}
 
// This code is contributed by Samim Hossain Mondal.


Python3




# Python3 program for the above approach
 
# Array for memoization
dp = []
 
# recursive function to calculate the
# minimum cost using dynamic programming
def minCostUtil(a, n, b, m, c, removed):
    global dp
 
    # Base Case - reached the end of the string
    if n == 0 or m == 0:
        # removed 0 characters
        # return high +ve value
        if removed == 0:
            return 99999
        return 0
 
    # return pre - calculated value
    if dp[n][m][int(bool(removed))] != -1:
        return dp[n][m][int(bool(removed))]
 
    # 1. Removing the character from A and
    # adding the cost
    # 2. Moving forward to remove some other
    # character and decrease the counter as
    # this character will not be removed.
    if a[n - 1] == b[m - 1]:
        dp[n][m][int(bool(removed))] = min(c[n - 1] + minCostUtil(a, n - 1,
                                                                  b, m, c, removed), minCostUtil(a, n - 1, b, m - 1, c, removed - 1))
        return dp[n][m][int(bool(removed))]
 
    # if no match, then move through string
    # A and try removing some other
    # character which matches, ie, can be
    # part of the subsequence that is equal to B
    else:
        dp[n][m][int(bool(removed))] = minCostUtil(a, n - 1, b, m, c, removed)
        return dp[n][m][int(bool(removed))]
 
# function to calculate minimum bed
def minCost(a, b, c):
    global dp
    for i in range(101):
        dp.append([])
        for j in range(101):
            dp[i].append([])
            for k in range(2):
                dp[i][j].append(-1)
 
    return minCostUtil(a, len(a), b, len(b), c, len(b))
 
# Driver Code
A = "abccdabccdabccd"
B = "bccd"
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
print(minCost(A, B, arr))
 
# This code is contributed by phasing17


C#




// C# program for the above approach
using System;
 
public class GFG{
 
  // Array for memoization
  static int[,,] dp = new int[101, 101, 2];
 
  // Recursive function to calculate
  // the minimum cost using dynamic programming
  static int minCostUtil(string a, int n, string b, int m,
                         int[] c, int removed)
  {
 
    // Base case reached the end of string
    if (n == 0 || m == 0) {
 
      // Removed 0 characters
      // return high (+)ve value
      if (removed == 0)
        return 99999;
      return 0;
    }
 
    // Return pre-calculated value
    if (dp[n, m, removed > 0 ? 1 : 0] != -1)
      return dp[n, m, removed > 0 ? 1 : 0];
 
    // If characters match return the minimum of
    // 1. Removing the character from A and
    // adding the cost
    // 2. Moving forward to remove some other
    // character and decrease the counter as
    // this character will not be removed.
    if (a[n - 1] == b[m - 1]) {
      dp[n, m, removed > 0 ? 1 : 0]
        = Math.Min(c[n - 1]
                   + minCostUtil(a, n - 1, b, m,
                                 c, removed),
                   minCostUtil(a, n - 1, b, m - 1,
                               c, removed - 1));
      return dp[n, m, removed > 0 ? 1 : 0];
    }
 
    // If no match then move through string
    // A and try removing some other
    // character which matches, i.e can be
    // part of the subsequence that is equal to B
    else
      return dp[n, m, removed > 0 ? 1 : 0]
      = minCostUtil(a, n - 1, b, m, c, removed);
  }
 
  // Function to calculate minimum cost
  static int minCost(string a, string b, int[] c)
  {
    for (int i = 0; i < 101; i++) {
      for (int j = 0; j < 101; j++) {
        for (int k = 0; k < 2; k++) {
          dp[i, j, k] = -1;
        }
      }
    }
    return minCostUtil(a, a.Length, b, b.Length, c,
                       b.Length);
  }
 
  // Driver code
  static public void Main (){
 
    string A = "abccdabccdabccd";
    string B = "bccd";
    int[] arr = { 1, 2,  3,  4,  5,  6,  7, 8,
                 9, 10, 11, 12, 13, 14, 15 };
 
    Console.Write(minCost(A, B, arr));
  }
}
 
// This code is contributed by hrithikgarg03188.


Javascript




// JavaScript program for the above approach
 
// Array for memoization
var dp = [];
 
// Recursive function to calculate
// the minimum cost using dynamic programming
function minCostUtil(a, n, b, m, c, removed)
{
    // Base case reached the end of string
    if (n == 0 || m == 0) {
        // Removed 0 characters
        // return high (+)ve value
        if (removed == 0)
            return 99999;
        return 0;
    }
 
    // Return pre-calculated value
    if (dp[n][m][Number(Boolean(removed))] != -1)
        return dp[n][m][(removed > 0) ? 1 : 0];
    // If characters match return the minimum of
    // 1. Removing the character from A and
    // adding the cost
    // 2. Moving forward to remove some other
    // character and decrease the counter as
    // this character will not be removed.
    if (a[n - 1] == b[m - 1]) {
        dp[n][m][(removed > 0) ? 1 : 0] = Math.min(
            c[n - 1]
                + minCostUtil(a, n - 1, b, m, c, removed),
            minCostUtil(a, n - 1, b, m - 1, c,
                        removed - 1));
        return dp[n][m][(removed > 0) ? 1 : 0];
    }
    // If no match then move through string
    // A and try removing some other
    // character which matches, i.e can be
    // part of the subsequence that is equal to B
    else
        return dp[n][m][(removed > 0) ? 1 : 0]
               = minCostUtil(a, n - 1, b, m, c, removed);
}
// Function to calculate minimum cost
 
function minCost(a, b, c)
{
    for (var i = 0; i < 101; i++) {
        dp[i] = [];
        for (var j = 0; j < 101; j++) {
            dp[i].push([]);
            for (var k = 0; k < 2; k++) {
                dp[i][j].push([-1]);
            }
        }
    }
 
    return minCostUtil(a, a.length, b, b.length, c,
                       b.length);
}
 
// Driver code
var A = "abccdabccdabccd";
var B = "bccd";
var arr =
    [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ];
document.write(minCost(A, B, arr));
 
// This code is contributed by phasing17


Output

21

Time Complexity: O(N*M)
Auxiliary Space: O(N*M)


My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!