Open In App

Minimum deletions to make String S the Subsequence of any String in the Set D

Last Updated : 14 Sep, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a string S and a set of strings D, the task is to find the minimum number of deletions required to make the string S a subsequence of any string in the set D, such that the deletion can only be performed on the substring of S.

Examples:

Input: string S = “abcdefg”, vector<string> D = {“abc”, “defg”, “ghi”}
Output: Minimum Deletion = 3
Explanation: This happens because the longest common subsequence is “defg” and its length is 4, and the length of the given string S is 7, so 7 – 4 = 3

Input: string S = “abcdefg”, vector<string> D = {“abc”, “defg”, “ghi”, “abcdefg”}
Output: Minimum Deletion = 0
Explanation: Since the string “abcdefg” is already present in the set of strings, the minimum number of deletions required will be 0, as no deletions need to be made to make S a subsequence of any string in the set D.

Input: string S = “abcdefg”, vector<string> D = {“ty”, “lk”, “mp”}
Output: Minimum Deletion = 7
Explanation: This happens because there is no common subsequence in set of strings D.

Approach: It’s important to note that this problem could be an NP-hard problem and can be solved following the below observations:

Observations:

  • An efficient approach uses the concept of dynamic programming. One way to approach this is to use a 2D array, where the rows represent the characters of the string S and the columns represent the characters of the strings in set D.
  • The value at each cell in the array represents the longest common subsequence between the substring of S up to that point and the string in the set D up to that point. If the current character in S and the current character in the string from the set D match, then the value at the current cell is the value at the cell above and to the left plus 1. 
  • If they do not match, then the value is the maximum of the value in the cell above and the value in the cell to the left.
  • Once the 2D array is built, the minimum number of deletions required to make S a subsequence of any string in the set D is the length of S minus the maximum value in the array.

Follow the below steps to solve the problem:

  • The first step is to define the function “minDeletions”, which takes two arguments, “S” (the original string), and “D” (the set of strings).
  • The function starts by declaring two variables, “n” and “m”, which store the length of string S and D[i] respectively.
  • The function then creates a 2D vector “dp” to store the length of the longest common subsequence (LCS) between S and D[i].
  • The function uses nested for loops to iterate over the characters of S and D[i] and uses the dynamic programming approach to calculate the LCS.
  • If the characters in S and D[i] are the same, the length of the LCS is incremented. If the characters are not the same, the length of the LCS is stored as the maximum between the two lengths stored in the previous cells of the dp vector.
  • The function returns the minimum number of deletions required, which is equal to the length of S minus the length of the LCS.
  • The main function starts by checking if the whole string S is present in the set of strings D. If it is, the output is 0, and the program exits.
  • If S is not present in the set of strings D, the main function calculates the minimum number of deletions required for each string in the set and stores the result in the “mm” variable. The final result is the minimum of all these values.
  • Finally, the output is printed, and the program ends.

Below is the implementation of the above approach:

C++




#include <bits/stdc++.h>
using namespace std;
 
// Returns length of Longest
// Common Subsequence
int minDeletions(string S, string D)
{
    int n = S.size();
    int m = D.size();
 
    // 2D array to store the length
    // of the lCS
    vector<vector<int> > dp(n + 1, vector<int>(m + 1, 0));
 
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (S[i - 1] == D[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            }
            else {
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }
 
    // Returns minimum deletions required
    return n - dp[n][m];
}
 
// Driver program to test above function
int main()
{
    string S = "abcdefg";
    vector<string> D = { "abc", "defg", "ghi" };
 
    // Check if the whole string S is in
    // set of strings D
    for (string d : D) {
        if (S == d) {
            cout << 0 << endl;
            exit(0);
        }
    }
 
    int mm = S.size();
    for (int i = 0; i < D.size(); i++) {
        mm = min(mm, minDeletions(S, D[i]));
    }
    cout << mm << endl;
    return 0;
}


Java




import java.util.Arrays;
 
class GFG {
    static int minDeletions(String S, String D)
    {
        int n = S.length();
        int m = D.length();
 
        int dp[][] = new int[n + 1][m + 1];
 
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                if (S.charAt(i - 1) == D.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }
                else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
 
        return n - dp[n][m];
    }
 
    public static void main(String[] args)
    {
        String S = "abcdefg";
        String D[] = { "abc", "defg", "ghi" };
 
        for (String d : D) {
            if (S.equals(d)) {
                System.out.println(0);
                System.exit(0);
            }
        }
 
        int mm = S.length();
        for (int i = 0; i < D.length; i++) {
            mm = Math.min(mm, minDeletions(S, D[i]));
        }
 
        System.out.println(mm);
    }
}
 
// This code is contributed by Susobhan Akhuli


Python




# Returns length of Longest Common Subsequence
def minDeletions(S, D):
    n = len(S)
    m = len(D)
 
    # 2D array to store the length of the lCS
    dp = [[0 for j in range(m + 1)] for i in range(n + 1)]
 
    for i in range(1, n + 1):
        for j in range(1, m + 1):
            if S[i - 1] == D[j - 1]:
                dp[i][j] = dp[i - 1][j - 1] + 1
            else:
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
 
    # Returns minimum deletions required
    return n - dp[n][m]
 
 
if __name__ == '__main__':
    S = "abcdefg"
    D = ["abc", "defg", "ghi"]
 
    for d in D:
        if S == d:
            print(0)
            exit(0)
 
    mm = len(S)
    for i in range(len(D)):
        mm = min(mm, minDeletions(S, D[i]))
 
    print(mm)
 
# This code is contributed by Susobhan Akhuli


C#




using System;
using System.Collections.Generic;
 
namespace LCS {
class Program {
    static int MinDeletions(string S, string D)
    {
        int n = S.Length;
        int m = D.Length;
 
        int[, ] dp = new int[n + 1, m + 1];
 
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                if (S[i - 1] == D[j - 1]) {
                    dp[i, j] = dp[i - 1, j - 1] + 1;
                }
                else {
                    dp[i, j] = Math.Max(dp[i - 1, j],
                                        dp[i, j - 1]);
                }
            }
        }
 
        return n - dp[n, m];
    }
 
    static void Main(string[] args)
    {
        string S = "abcdefg";
        List<string> D
            = new List<string>{ "abc", "defg", "ghi" };
 
        foreach(string d in D)
        {
            if (S == d) {
                Console.WriteLine(0);
                Environment.Exit(0);
            }
        }
 
        int mm = S.Length;
        for (int i = 0; i < D.Count; i++) {
            mm = Math.Min(mm, MinDeletions(S, D[i]));
        }
        Console.WriteLine(mm);
    }
}
}
 
// This code is contributed by Susobhan Akhuli


Javascript




<script>
function minDeletions(S, D) {
  let n = S.length;
  let m = D.length;
   
  // 2D array to store the length of the LCS
  let dp = Array(n + 1)
    .fill(0)
    .map(() => Array(m + 1).fill(0));
 
  for (let i = 1; i <= n; i++) {
    for (let j = 1; j <= m; j++) {
      if (S[i - 1] === D[j - 1]) {
        dp[i][j] = dp[i - 1][j - 1] + 1;
      } else {
        dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
      }
    }
  }
 
  // Returns minimum deletions required
  return n - dp[n][m];
}
 
// Driver program to test above function
let S = "abcdefg";
let D = ["abc", "defg", "ghi"];
 
for (let d of D) {
  if (S === d) {
    document.write(0);
    process.exit(0);
  }
}
 
let mm = S.length;
for (let i = 0; i < D.length; i++) {
  mm = Math.min(mm, minDeletions(S, D[i]));
}
document.write(mm);
 
// This code is contributed by Susobhan Akhuli
</script>


Output

3








Time Complexity: O(len(S)*len(D[i])*len(D))
Auxiliary Space: O(len(S)*len(D[i])) 

Efficient approach: Space optimization

In the previous approach, the current value dp[i][j] is only depend upon the current and previous row values of DP. So to optimize the space complexity we use a single 1D array to store the computations.

Implementation steps:

  • Create a 1D vector DP of size m+1.
  • Set a base case by initializing the values of DP to 0.
  • Now iterate over subproblems by the help of nested loop and get the current value from previous computations.
  • Now initialize variables prev and curr used to store the previous and current value of Dp.
  • After every iteration assign the value of curr to prev for further iteration.
  • At last return final answer store in n – dp[m].

Implementation: 

C++




#include <bits/stdc++.h>
using namespace std;
 
// Returns length of Longest
// Common Subsequence
int minDeletions(string S, string D)
{
    int n = S.size();
    int m = D.size();
 
    // 1D array to store the length
    // of the lCS
    vector<int> dp(m + 1, 0);
 
    for (int i = 1; i <= n; i++) {
        int prev = 0;
        for (int j = 1; j <= m; j++) {
            int curr = dp[j];
            if (S[i - 1] == D[j - 1]) {
                dp[j] = prev + 1;
            }
            else {
                dp[j] = max(dp[j - 1], dp[j]);
            }
            prev = curr;
        }
    }
 
    // Returns minimum deletions required
    return n - dp[m];
}
 
// Driver program to test above function
int main()
{
    string S = "abcdefg";
    vector<string> D = { "abc", "defg", "ghi" };
 
    // Check if the whole string S is in
    // set of strings D
    for (string d : D) {
        if (S == d) {
            cout << 0 << endl;
            exit(0);
        }
    }
 
    int mm = S.size();
    for (int i = 0; i < D.size(); i++) {
        mm = min(mm, minDeletions(S, D[i]));
    }
    cout << mm << endl;
    return 0;
}
 
// -- By bhardwajji


Java




import java.io.*;
import java.util.*;
public class Main {
    public static int minDeletions(String S, String D) {
        int n = S.length();
        int m = D.length();
        // 1D array to store the length
        // of the LCS
        int[] dp = new int[m + 1];
        for (int i = 1; i <= n; i++) {
            int prev = 0;
            for (int j = 1; j <= m; j++) {
                int curr = dp[j];
                if (S.charAt(i - 1) == D.charAt(j - 1)) {
                    dp[j] = prev + 1;
                } else {
                    dp[j] = Math.max(dp[j - 1], dp[j]);
                }
                prev = curr;
            }
        }
        // Returns minimum deletions required
        return n - dp[m];
    }
    // Driver program to test above function
    public static void main(String[] args) {
        String S = "abcdefg";
        List<String> D = new ArrayList<>();
        D.add("abc");
        D.add("defg");
        D.add("ghi");
        // Check if the whole string S is in
        // set of strings D
        for (String d : D) {
            if (S.equals(d)) {
                System.out.println(0);
                System.exit(0);
            }
        }
        int mm = S.length();
        for (String d : D) {
            mm = Math.min(mm, minDeletions(S, d));
        }
        System.out.println(mm);
    }
}


Python3




# Python program of the above approach
from typing import List
 
# Returns length of Longest
# Common Subsequence
def minDeletions(S: str, D: str) -> int:
    n = len(S)
    m = len(D)
 
    # 1D array to store the length
    # of the lCS
    dp = [0] * (m + 1)
 
    for i in range(1, n + 1):
        prev = 0
        for j in range(1, m + 1):
            curr = dp[j]
            if S[i - 1] == D[j - 1]:
                dp[j] = prev + 1
            else:
                dp[j] = max(dp[j - 1], dp[j])
            prev = curr
 
    # Returns minimum deletions required
    return n - dp[m]
 
# Driver program to test above function
if __name__ == "__main__":
    S = "abcdefg"
    D = ["abc", "defg", "ghi"]
 
    # Check if the whole string S is in
    # set of strings D
    for d in D:
        if S == d:
            print(0)
            exit(0)
 
    mm = len(S)
    for i in range(len(D)):
        mm = min(mm, minDeletions(S, D[i]))
    print(mm)
     
# This code is contributed by Susobhan Akhuli


C#




// C# code of the above approach
using System;
using System.Collections.Generic;
using System.Linq;
 
public class GFG {
    // Returns length of Longest
    // Common Subsequence
    public static int MinDeletions(string S, string D)
    {
        int n = S.Length;
        int m = D.Length;
 
        // 1D array to store the length
        // of the lCS
        List<int> dp = Enumerable.Repeat(0, m + 1).ToList();
 
        for (int i = 1; i <= n; i++) {
            int prev = 0;
            for (int j = 1; j <= m; j++) {
                int curr = dp[j];
                if (S[i - 1] == D[j - 1]) {
                    dp[j] = prev + 1;
                }
                else {
                    dp[j] = Math.Max(dp[j - 1], dp[j]);
                }
                prev = curr;
            }
        }
 
        // Returns minimum deletions required
        return n - dp[m];
    }
 
    // Driver program to test above function
    public static void Main()
    {
        string S = "abcdefg";
        List<string> D
            = new List<string>() { "abc", "defg", "ghi" };
 
        // Check if the whole string S is in
        // set of strings D
        foreach(string d in D)
        {
            if (S == d) {
                Console.WriteLine(0);
                Environment.Exit(0);
            }
        }
 
        int mm = S.Length;
        for (int i = 0; i < D.Count; i++) {
            mm = Math.Min(mm, MinDeletions(S, D[i]));
        }
        Console.WriteLine(mm);
    }
}
 
// This code is contributed by Susobhan Akhuli


Javascript




// Returns length of Longest
// Common Subsequence
function minDeletions(S, D) {
  let n = S.length;
  let m = D.length;
 
  // 1D array to store the length
  // of the LCS
  let dp = Array(m + 1).fill(0);
 
  for (let i = 1; i <= n; i++) {
    let prev = 0;
    for (let j = 1; j <= m; j++) {
      let curr = dp[j];
      if (S[i - 1] === D[j - 1]) {
        dp[j] = prev + 1;
      } else {
        dp[j] = Math.max(dp[j - 1], dp[j]);
      }
      prev = curr;
    }
  }
 
  // Returns minimum deletions required
  return n - dp[m];
}
 
// Driver program
let S = "abcdefg";
let D = ["abc", "defg", "ghi"];
 
// Check if the whole string S is in
// set of strings D
for (let d of D) {
  if (S === d) {
    console.log(0);
    process.exit(0);
  }
}
 
let mm = S.length;
for (let i = 0; i < D.length; i++) {
  mm = Math.min(mm, minDeletions(S, D[i]));
}
console.log(mm);
 
// This code is contributed by Susobhan Akhuli


Output

3

Time Complexity: O(n*m) , n is len(S) and m is len(D)
Auxiliary Space: O(m) 



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

Similar Reads