Open In App

Find the LCS of string such that it does not contains the given string

Last Updated : 24 Feb, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given three strings s1, s2 and s3. The task is to compute the Longest Common Subsequence of the string s1 and s2, such that it does not contain s3 as a substring. If there is no valid common subsequence, output -1.

Examples:

Input: s1 = “AJKEQSLOBSROFGZ”, s2 = “OVGURWZLWVLUXTH”, s3 = “OZ”
Output: ORZ
Explanation: “ORZ” is the Longest Common Subsequence which does not have “OZ” as a substring.

Input: s1 = AA, s2 = “A”, s3 = “A”
Output: -1
Explanation: There is no possible Common Substring between s1 and s2 that does not contain s3.

Approach: The problem can be solved using the following approach:

The problem requires finding the Longest Common Subsequence of two strings, s1 and s2, such that the resulting subsequence does not contain s3 as a substring. The solution involves using Dynamic Programming to efficiently compute the length of the longest common subsequence.

Failure Function (KMP): Calculate the failure function for string s3 using the Knuth–Morris–Pratt (KMP) algorithm. This function helps in efficiently matching characters when finding the longest common subsequence.

Dynamic Programming: Use a three-dimensional DP array, dp[i][j][k], to store the length of the longest common subsequence of prefixes s1[0…i], s2[0…j], and s3[0…k]. The state dp[i][j][k] represents the length of the longest common subsequence considering the first i characters of s1, the first j characters of s2, and the first k characters of s3.

Iterate over the lengths of s1, s2, and s3, updating the DP array based on the characters. If s1[i] matches s2[j], update the DP array based on the failure function of s3 to ensure that the longest common subsequence does not contain s3 as a substring.

Result: After the dynamic programming loop, find the longest common subsequence by considering the lengths of s1, s2, and s3. Output the result.

Step-by-step approach:

  • Calculate Failure Function (KMP): Use the Knuth–Morris–Pratt (KMP) algorithm to calculate the failure function for string s3. This helps efficiently match characters when finding the longest common subsequence.
  • Dynamic Programming Initialization: Create a three-dimensional DP array, dp[i][j][k], to store the length of the longest common subsequence. Initialize dp[i][j][k] to empty string for all indices.
  • Dynamic Programming Loop:
    • Iterate over the lengths of s1, s2, and s3.
    • Update the DP array based on the characters of s1, s2, and s3.
    • If s1[i] matches s2[j], update the DP array based on the failure function of s3 to avoid having s3 as a substring.
  • Find Longest Common Subsequence: After the dynamic programming loop, find the longest common subsequence by considering the lengths of s1, s2, and s3.
  • If the longest common subsequence is empty, output “-1”; otherwise, print the result.

Below is the implementation of the above approach:

C++




#include <bits/stdc++.h>
using namespace std;
 
string s1, s2, s3, dp[111][111][111],
    longestCommonSubsequence;
 
// Failure function for KMP algorithm
int failureFunction[111];
 
// Function to update a string with a longer one
void updateString(string& target, string source)
{
    if (target.size() < source.size())
        target = source;
}
 
// Function to find the Longest Common Subsequence of the
// string s1 and s2, such that it does not contain s3 as a
// substring
void solve()
{
 
    int lenS1 = s1.size(), lenS2 = s2.size(),
        lenS3 = s3.size(), j = 0;
 
    // Calculate the failure function for s3 using KMP
    // algorithm
    for (int i = 1; i < lenS3; i++) {
        while (j > 0 && s3[i] != s3[j])
            j = failureFunction[j - 1];
        if (s3[i] == s3[j])
            failureFunction[i] = ++j;
    }
 
    // Dynamic programming loop to find the longest common
    // subsequence
    for (int i = 1; i <= lenS1; i++)
        for (int j = 1; j <= lenS2; j++)
            for (int k = 0; k < lenS3; k++) {
                if (s1[i - 1] == s2[j - 1]) {
                    char currentChar = s1[i - 1];
                    int temp = k;
                    while (temp > 0
                           && currentChar != s3[temp])
                        temp = failureFunction[temp - 1];
                    if (currentChar == s3[temp])
                        temp++;
                    updateString(dp[i][j][temp],
                                 dp[i - 1][j - 1][k]
                                     + currentChar);
                }
                updateString(dp[i][j][k], dp[i - 1][j][k]);
                updateString(dp[i][j][k], dp[i][j - 1][k]);
            }
 
    // Find the longest common subsequence that does not
    // contain s3 as a substring
    for (int i = 0; i < lenS3; i++)
        updateString(longestCommonSubsequence,
                     dp[lenS1][lenS2][i]);
 
    // Output the result
    if (longestCommonSubsequence.size() == 0)
        puts("-1");
    else
        printf("%s\n", longestCommonSubsequence.c_str());
}
 
// Driver code
int main()
{
    s1 = "AJKEQSLOBSROFGZ";
    s2 = "OVGURWZLWVLUXTH";
    s3 = "OZ";
 
    solve();
 
    return 0;
}


Java




// Java program for the above approach
import java.util.Arrays;
 
public class GFG {
    static String s1, s2, s3;
    static String[][][] dp;
    static String longestCommonSubsequence;
    static int[] failureFunction;
 
    public static void main(String[] args)
    {
        s1 = "AJKEQSLOBSROFGZ";
        s2 = "OVGURWZLWVLUXTH";
        s3 = "OZ";
 
        solve();
    }
 
    // Function to update a string with a longer one
    static String updateString(String target, String source)
    {
        if (target.length() < source.length()) {
            return source;
        }
        return target;
    }
 
    // Function to find the Longest Common Subsequence of
    // the string s1 and s2, such that it does not contain
    // s3 as a substring
    static void solve()
    {
        int lenS1 = s1.length();
        int lenS2 = s2.length();
        int lenS3 = s3.length();
        int j = 0;
 
        // Calculate the failure function for s3 using KMP
        // algorithm
        failureFunction = new int[111];
        Arrays.fill(failureFunction, 0);
        for (int i = 1; i < lenS3; i++) {
            while (j > 0 && s3.charAt(i) != s3.charAt(j)) {
                j = failureFunction[j - 1];
            }
            if (s3.charAt(i) == s3.charAt(j)) {
                failureFunction[i] = ++j;
            }
        }
 
        // Dynamic programming loop to find the longest
        // common subsequence
        dp = new String[111][111][111];
        for (String[][] row : dp) {
            for (String[] col : row) {
                Arrays.fill(col, "");
            }
        }
        for (int i = 1; i <= lenS1; i++) {
            for (j = 1; j <= lenS2; j++) {
                for (int k = 0; k < lenS3; k++) {
                    if (s1.charAt(i - 1)
                        == s2.charAt(j - 1)) {
                        char currentChar = s1.charAt(i - 1);
                        int temp = k;
                        while (temp > 0
                               && currentChar
                                      != s3.charAt(temp)) {
                            temp
                                = failureFunction[temp - 1];
                        }
                        if (currentChar
                            == s3.charAt(temp)) {
                            temp++;
                        }
                        dp[i][j][temp] = updateString(
                            dp[i][j][temp],
                            dp[i - 1][j - 1][k]
                                + currentChar);
                    }
                    dp[i][j][k] = updateString(
                        dp[i][j][k], dp[i - 1][j][k]);
                    dp[i][j][k] = updateString(
                        dp[i][j][k], dp[i][j - 1][k]);
                }
            }
        }
 
        // Find the longest common subsequence that does not
        // contain s3 as a substring
        longestCommonSubsequence = "";
        for (int i = 0; i < lenS3; i++) {
            longestCommonSubsequence
                = updateString(longestCommonSubsequence,
                               dp[lenS1][lenS2][i]);
        }
 
        // Output the result
        if (longestCommonSubsequence.length() == 0) {
            System.out.println("-1");
        }
        else {
            System.out.println(longestCommonSubsequence);
        }
    }
}
// This code is contributed by Susobhan Akhuli


Python3




# Python program for the above approach
def updateString(target, source):
    if len(target) < len(source):
        return source
    return target
 
def solve(longestCommonSubsequence):
    lenS1 = len(s1)
    lenS2 = len(s2)
    lenS3 = len(s3)
    j = 0
 
    for i in range(1, lenS3):
        while j > 0 and s3[i] != s3[j]:
            j = failureFunction[j - 1]
        if s3[i] == s3[j]:
            j += 1
            failureFunction[i] = j
 
    for i in range(1, lenS1 + 1):
        for j in range(1, lenS2 + 1):
            for k in range(lenS3 + 1):  # Adjusted loop range
                if k < lenS3:
                    if s1[i - 1] == s2[j - 1]:
                        currentChar = s1[i - 1]
                        temp = k
                        while temp > 0 and currentChar != s3[temp]:
                            temp = failureFunction[temp - 1]
                        if currentChar == s3[temp]:
                            temp += 1
                        dp[i][j][temp] = updateString(dp[i][j][temp], dp[i - 1][j - 1][k] + currentChar)
                dp[i][j][k] = updateString(dp[i][j][k], dp[i - 1][j][k])
                dp[i][j][k] = updateString(dp[i][j][k], dp[i][j - 1][k])
 
    for i in range(lenS3):
        longestCommonSubsequence = updateString(longestCommonSubsequence, dp[lenS1][lenS2][i])
 
    if len(longestCommonSubsequence) == 0:
        print("-1")
    else:
        print(longestCommonSubsequence)
 
s1 = "AJKEQSLOBSROFGZ"
s2 = "OVGURWZLWVLUXTH"
s3 = "OZ"
 
dp = [[["" for _ in range(len(s3) + 1)] for _ in range(len(s2) + 1)] for _ in range(len(s1) + 1)]  # Adjusted array dimensions
longestCommonSubsequence = ""
failureFunction = [0] * len(s3)
 
solve(longestCommonSubsequence)
 
# This code is contributed by Susobhan Akhuli


C#




// C# program for the above approach
using System;
 
public class GFG {
    static string s1, s2, s3;
    static string[][][] dp;
    static string longestCommonSubsequence;
    static int[] failureFunction;
 
    public static void Main(string[] args)
    {
        s1 = "AJKEQSLOBSROFGZ";
        s2 = "OVGURWZLWVLUXTH";
        s3 = "OZ";
 
        Solve();
    }
 
    // Function to update a string with a longer one
    static string UpdateString(string target, string source)
    {
        if (target.Length < source.Length) {
            return source;
        }
        return target;
    }
 
    // Function to find the Longest Common Subsequence of
    // the string s1 and s2, such that it does not contain
    // s3 as a substring
    static void Solve()
    {
        int lenS1 = s1.Length;
        int lenS2 = s2.Length;
        int lenS3 = s3.Length;
        int j = 0;
 
        // Calculate the failure function for s3 using KMP
        // algorithm
        failureFunction = new int[111];
        Array.Fill(failureFunction, 0);
        for (int i = 1; i < lenS3; i++) {
            while (j > 0 && s3[i] != s3[j]) {
                j = failureFunction[j - 1];
            }
            if (s3[i] == s3[j]) {
                failureFunction[i] = ++j;
            }
        }
 
        // Dynamic programming loop to find the longest
        // common subsequence
        dp = new string[111][][];
        for (int i = 0; i < 111; i++) {
            dp[i] = new string[111][];
            for (int k = 0; k < 111; k++) {
                dp[i][k] = new string[111];
                for (int l = 0; l < 111; l++) {
                    dp[i][k][l] = "";
                }
            }
        }
        for (int i = 1; i <= lenS1; i++) {
            for (j = 1; j <= lenS2; j++) {
                for (int k = 0; k < lenS3; k++) {
                    if (s1[i - 1] == s2[j - 1]) {
                        char currentChar = s1[i - 1];
                        int temp = k;
                        while (temp > 0
                               && currentChar != s3[temp]) {
                            temp
                                = failureFunction[temp - 1];
                        }
                        if (currentChar == s3[temp]) {
                            temp++;
                        }
                        dp[i][j][temp] = UpdateString(
                            dp[i][j][temp],
                            dp[i - 1][j - 1][k]
                                + currentChar);
                    }
                    dp[i][j][k] = UpdateString(
                        dp[i][j][k], dp[i - 1][j][k]);
                    dp[i][j][k] = UpdateString(
                        dp[i][j][k], dp[i][j - 1][k]);
                }
            }
        }
 
        // Find the longest common subsequence that does not
        // contain s3 as a substring
        longestCommonSubsequence = "";
        for (int i = 0; i < lenS3; i++) {
            longestCommonSubsequence
                = UpdateString(longestCommonSubsequence,
                               dp[lenS1][lenS2][i]);
        }
 
        // Output the result
        if (longestCommonSubsequence.Length == 0) {
            Console.WriteLine("-1");
        }
        else {
            Console.WriteLine(longestCommonSubsequence);
        }
    }
}
 
// This code is contributed by Susobhan Akhuli


Javascript




let s1, s2, s3;
let dp = new Array(111).fill(null).map(() =>
  new Array(111).fill(null).map(() => new Array(111).fill(''))
);
let longestCommonSubsequence = '';
 
// Failure function for KMP algorithm
let failureFunction = new Array(111).fill(0);
 
// Function to update a string with a longer one
function updateString(target, source) {
  if (target.length < source.length) {
    return source;
  }
  return target;
}
 
// Function to find the Longest Common Subsequence of the
// string s1 and s2, such that it does not contain s3 as a
// substring
function solve() {
  const lenS1 = s1.length,
    lenS2 = s2.length,
    lenS3 = s3.length;
  let j = 0;
 
  // Calculate the failure function for s3 using KMP algorithm
  for (let i = 1; i < lenS3; i++) {
    while (j > 0 && s3[i] !== s3[j]) {
      j = failureFunction[j - 1];
    }
    if (s3[i] === s3[j]) {
      failureFunction[i] = ++j;
    }
  }
 
  // Dynamic programming loop to find the longest common subsequence
  for (let i = 1; i <= lenS1; i++) {
    for (let j = 1; j <= lenS2; j++) {
      for (let k = 0; k < lenS3; k++) {
        if (s1[i - 1] === s2[j - 1]) {
          let currentChar = s1[i - 1];
          let temp = k;
          while (temp > 0 && currentChar !== s3[temp]) {
            temp = failureFunction[temp - 1];
          }
          if (currentChar === s3[temp]) {
            temp++;
          }
          dp[i][j][temp] = updateString(dp[i][j][temp], dp[i - 1][j - 1][k] + currentChar);
        }
        dp[i][j][k] = updateString(dp[i][j][k], dp[i - 1][j][k]);
        dp[i][j][k] = updateString(dp[i][j][k], dp[i][j - 1][k]);
      }
    }
  }
 
  // Find the longest common subsequence that does not contain s3 as a substring
  for (let i = 0; i < lenS3; i++) {
    longestCommonSubsequence = updateString(longestCommonSubsequence, dp[lenS1][lenS2][i]);
  }
 
  // Output the result
  if (longestCommonSubsequence.length === 0) {
    console.log("-1");
  } else {
    console.log(longestCommonSubsequence);
  }
}
 
// Driver code
function main() {
  s1 = "AJKEQSLOBSROFGZ";
  s2 = "OVGURWZLWVLUXTH";
  s3 = "OZ";
 
  solve();
}
 
main();


Output

ORZ


Time complexity: O(n * m * p), where n, m, p are the length of string s1, s2 and s3 respectively.
Auxiliary space: O(n * m * p),



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads