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


We are given two strings string A and string B along with an array that represents the cost to delete the ith character of the given string A. We need to delete some characters of string A (possibly zero or none) with the minimum cost such that no subsequence of A represents string B. We are going to see three approaches to implementing the code that is the recursive approach; the recursive and memoization approach; and tabulation or iterative dp.

Example

Let's have a look at the following example −

Input

string a = "xanxd"
string b = "xd" 
int cost[] = {1, 2, 3, 4, 5}

Output

5

Explanation

Here we are required to remove all the occurrences of the 'xd' from the string A as the subsequence and to do so we have two methods either we can remove 'd' from the given string and this will lead to cost 5 or we have to remove both 'x' that will again cost 1 + 4 that is 5.

Recursive Approach

In this approach, we are going to create a recursive function, which will take a current index of both strings and both strings as the parameter along with the number of indexes of the second string removed. There will be two different cases and both of them are handled separately.

If both the characters of the current string are same at any position, then we have to make decision either to remove the current character of string A with given cost otherwise we can skip this one and will not make any change in the removed variable.

If both characters are not same then we don't need to remove, then and will directly move to the next character of the string A.

Example

#include <bits/stdc++.h>
using namespace std;

// recursive function to get the required result 
int rec(string& a, string& b, int idx1, int idx2, vector<int>& cost, int rem){
   // base condition to check the edge cases 
   if(idx1 == 0 or idx2 == 0) {
      return rem == 0 ? 1e5:0;
   }	
   if(a[idx1 - 1] == b[idx2 - 1]){
      return min(cost[idx1-1] + rec(a,b, idx1-1, idx2, cost, rem), rec(a, b, idx1-1, idx2-1, cost, rem-1));
   } else {
      return rec(a, b, idx1-1, idx2, cost, rem);
   }
}
// function to get call to the recursive function 
int getCost(string a, string b, vector<int> cost){
   // calling to the recursive function 
   return rec(a, b, a.length(), b.length(), cost, b.length());
}
int main(){
   string a = "abccdabccdabccd"; // given string a
   string b = "bccd"; // given string b
   vector<int> cost = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; // given cost array    
   // calling to the function to get the result
   cout << "Minimum cost to delete characters from String A to remove any subsequence as String B is: " << getCost(a, b, cost);
   return 0;
}

Output

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

Time and Space Complexity

The time complexity of the above code is O(2^M) where M is the size of the given second string.

The space complexity of the above code is O(M) because we are making the recursive calls and the recursive stack stakes the memory.

Recursion + Memoization Approach

In this approach, we are going to store the results of the states that are already visited in the function call and will return that value for again calling that function leads to reduce time complexity from exponential to quadratic. Let us see the code for better understanding −

Example

#include <bits/stdc++.h>
using namespace std;

int memo[105][105][3]; // array to store results 
// recursive function to get the required result 
int rec(string& a, string& b, int idx1, int idx2, vector<int>& cost, int rem){
   // base condition to check the edge cases 
   if(idx1 == 0 or idx2 == 0) {
      return rem == 0 ? 1e5:0;
   }	
   int state = rem > 0 ? 1 : 0;
   if(memo[idx1][idx2][state] != -1){
      return memo[idx1][idx2][state]; 
   }
   if(a[idx1 - 1] == b[idx2 - 1]){
      memo[idx1][idx2][state] = min(cost[idx1-1] + rec(a,b, idx1-1, idx2, cost, rem), rec(a, b, idx1-1, idx2-1, cost, rem-1));
      return memo[idx1][idx2][state]; 
   } else {
      memo[idx1][idx2][state] = rec(a, b, idx1-1, idx2, cost, rem);
      return memo[idx1][idx2][state]; 
   }
}
// function to get call to the recursive function 
int getCost(string a, string b, vector<int> cost){
   memset(memo, -1, sizeof(memo));
   // calling to the recursive function 
   return rec(a, b, a.length(), b.length(), cost, b.length());
}
int main(){
   string a = "abccdabccdabccd"; // given string a
   string b = "bccd"; // given string b
   vector<int> cost = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; // given cost array   
   // calling to the function to get the result
   cout << "Minimum cost to delete characters from String A to remove any subsequence as String B is:" << getCost(a, b, cost);
   return 0;
}

Output

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

Time and Space Complexity

The time complexity of the above code is O(N*M) where M is the size of the given second string and N is of the first string.

The space complexity of the above code is O(N*M) because we are using a 3-D array (which is approx of N*M size).

Conclusion

In this tutorial, we have implemented a problem to find the minimum cost to delete characters from given string A to remove any subsequence as of given string B. Where the cost of each character of string A is also given to us. First, we implemented a recursive approach then we updated it to a memoization approach where we stored the result of visited states and stored in an array to reduce time complexity.

Updated on: 24-Aug-2023

91 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements