从字符串 A 中删除字符以将任何子序列作为字符串 B 删除的最低成本
给定两个大小分别为N和M的字符串A和B ,其中B是子序列 的A和大小为N的数组arr[] ,其中arr[i]是 从字符串A中删除第 i 个字符的成本。任务是找到从A中删除字符的最小成本,使得删除后A的任何子序列都与B相同。
例子:
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”
方法:解决问题的简单方法是使用递归并根据以下想法找到A和B之间的公共子序列:
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.
按照下面提到的步骤来实现这个想法:
- 使用指针i递归遍历字符串A并保持指针j指向B 。
- 在每个递归函数中:
- 如果到达字符串的末尾,如果删除了任何字符(由已删除元素的计数器检查),则返回 0,否则返回高正值。
- 如果A[i] = B[j]有两种选择:
- 删除A[i]并添加成本arr[i]以回答并递归调用下一个元素。
- 保持A[i]并继续前进。
- 否则继续前进,直到A[i]匹配B[i] 。
- 从每个递归调用中返回上述两种情况中的最小成本。
- 返回最小成本作为答案。
时间复杂度: O(2 M )
辅助空间: O(1)
高效方法:上述方法的时间可以根据以下思想使用动态规划进一步优化:
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)
下面是上述方法的实现。
C++
// C++ program for the above approach
#include
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& 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& 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 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, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15 };
System.out.print(minCost(A, B, arr));
}
}
// This code is contributed by Samim Hossain Mondal.
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
21
时间复杂度: O(N*M)
辅助空间: O(N*M)