Open In App

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

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:

Below is the implementation of the above approach:




#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;
}




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




# 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




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




<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:

Implementation: 




#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




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);
    }
}




# 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# 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




// 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) 


Article Tags :