Sunday, November 17, 2024
Google search engine
HomeLanguagesDynamic ProgrammingCount ways to increase LCS length of two strings by one

Count ways to increase LCS length of two strings by one

Given two strings of lower alphabet characters, we need to find the number of ways to insert a character in the first string such that length of LCS of both strings increases by one. 

Examples:  

Input : str1 = “abab”, str2 = “abc”
Output : 3
LCS length of given two strings is 2.
There are 3 ways of insertion in str1, 
to increase the LCS length by one which 
are enumerated below, 
str1 = “abcab”    str2 = “abc”  LCS length = 3
str1 = “abacb”    str2 = “abc”  LCS length = 3
str1 = “ababc”    str2 = “abc”  LCS length = 3

Input : str1 = “abcabc”, str2 = “abcd”
Output : 4

The idea is try all 26 possible characters at each position of first string, if length of str1 is m then a new character can be inserted in (m + 1) positions, now suppose at any time character c is inserted at ith position in str1 then we will match it with all positions having character c in str2. Suppose one such position is j, then for total LCS length to be one more than previous, below condition should satisfy, 

LCS(str1[1, m], str2[1, n]) = LCS(str1[1, i],  str2[1, j-1]) + 
                              LCS(str1[i+1, m], str2[j+1, n])  

Above equation states that sum of LCS of the suffix and prefix substrings at inserted character must be same as total LCS of strings, so that when the same character is inserted in first string it will increase the length of LCS by one.
In below code two 2D arrays, lcsl and lcsr are used for storing LCS of prefix and suffix of strings respectively. Method for filling these 2D arrays can be found here

Please see below code for better understanding,  

C++




// C++ program to get number of ways to increase
// LCS by 1
#include <bits/stdc++.h>
using namespace std;
 
#define M 26
 
// Utility method to get integer position of lower
// alphabet character
int toInt(char ch)
{
    return (ch - 'a');
}
 
// Method returns total ways to increase LCS length by 1
int waysToIncreaseLCSBy1(string str1, string str2)
{
    int m = str1.length(), n = str2.length();
 
    // Fill positions of each character in vector
    vector<int> position[M];
    for (int i = 1; i <= n; i++)
        position[toInt(str2[i-1])].push_back(i);
 
    int lcsl[m + 2][n + 2];
    int lcsr[m + 2][n + 2];
 
    // Initializing 2D array by 0 values
    for (int i = 0; i <= m+1; i++)
        for (int j = 0; j <= n + 1; j++)
            lcsl[i][j] = lcsr[i][j] = 0;
 
    // Filling LCS array for prefix substrings
    for (int i = 1; i <= m; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (str1[i-1] == str2[j-1])
                lcsl[i][j] = 1 + lcsl[i-1][j-1];
            else
                lcsl[i][j] = max(lcsl[i-1][j],
                                lcsl[i][j-1]);
        }
    }
 
    // Filling LCS array for suffix substrings
    for (int i = m; i >= 1; i--)
    {
        for (int j = n; j >= 1; j--)
        {
            if (str1[i-1] == str2[j-1])
                lcsr[i][j] = 1 + lcsr[i+1][j+1];
            else
                lcsr[i][j] = max(lcsr[i+1][j],
                                 lcsr[i][j+1]);
        }
    }
 
    // Looping for all possible insertion positions
    // in first string
    int ways = 0;
    for (int i=0; i<=m; i++)
    {
        // Trying all possible lower case characters
        for (char c='a'; c<='z'; c++)
        {
            // Now for each character, loop over same
            // character positions in second string
            for (int j=0; j<position[toInt(c)].size(); j++)
            {
                int p = position[toInt(c)][j];
 
                // If both, left and right substrings make
                // total LCS then increase result by 1
                if (lcsl[i][p-1] + lcsr[i+1][p+1] == lcsl[m][n])
                    ways++;
            }
        }
    }
 
    return ways;
}
 
//  Driver code to test above methods
int main()
{
    string str1 = "abcabc";
    string str2 = "abcd";
    cout << waysToIncreaseLCSBy1(str1, str2);
    return 0;
}


Java




// Java program to get number of ways to increase
// LCS by 1
import java.util.*;
 
class GFG
{
    static int M = 26;
 
    // Method returns total ways to increase
    // LCS length by 1
    static int waysToIncreaseLCSBy1(String str1,
                                    String str2)
    {
        int m = str1.length(), n = str2.length();
 
        // Fill positions of each character in vector
        Vector<Integer>[] position = new Vector[M];
        for (int i = 0; i < M; i++)
            position[i] = new Vector<>();
 
        for (int i = 1; i <= n; i++)
            position[str2.charAt(i - 1) - 'a'].add(i);
 
        int[][] lcsl = new int[m + 2][n + 2];
        int[][] lcsr = new int[m + 2][n + 2];
 
        // Initializing 2D array by 0 values
        for (int i = 0; i <= m + 1; i++)
            for (int j = 0; j <= n + 1; j++)
                lcsl[i][j] = lcsr[i][j] = 0;
 
        // Filling LCS array for prefix substrings
        for (int i = 1; i <= m; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                if (str1.charAt(i - 1) == str2.charAt(j - 1))
                    lcsl[i][j] = 1 + lcsl[i - 1][j - 1];
                else
                    lcsl[i][j] = Math.max(lcsl[i - 1][j],
                                          lcsl[i][j - 1]);
            }
        }
 
        // Filling LCS array for suffix substrings
        for (int i = m; i >= 1; i--)
        {
            for (int j = n; j >= 1; j--)
            {
                if (str1.charAt(i - 1) == str2.charAt(j - 1))
                    lcsr[i][j] = 1 + lcsr[i + 1][j + 1];
                else
                    lcsr[i][j] = Math.max(lcsr[i + 1][j],
                                          lcsr[i][j + 1]);
            }
        }
 
        // Looping for all possible insertion positions
        // in first string
        int ways = 0;
        for (int i = 0; i <= m; i++)
        {
 
            // Trying all possible lower case characters
            for (char d = 0; d < 26; d++)
            {
 
                // Now for each character, loop over same
                // character positions in second string
                for (int j = 0; j < position[d].size(); j++)
                {
                    int p = position[d].elementAt(j);
 
                    // If both, left and right substrings make
                    // total LCS then increase result by 1
                    if (lcsl[i][p - 1] +
                        lcsr[i + 1][p + 1] == lcsl[m][n])
                        ways++;
                }
            }
        }
        return ways;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        String str1 = "abcabc";
        String str2 = "abcd";
        System.out.println(waysToIncreaseLCSBy1(str1, str2));
    }
}
 
// This code is contributed by
// sanjeev2552


Python3




# Python3 program to get number of ways to increase
# LCS by 1
 
M = 26
 
# Method returns total ways to increase LCS length by 1
def waysToIncreaseLCSBy1(str1, str2):
    m = len(str1)
    n = len(str2)
 
    # Fill positions of each character in vector
    # vector<int> position[M];
    position = [[] for i in range(M)]
    for i in range(1, n+1, 1):
        position[ord(str2[i-1])-97].append(i)
 
    # Initializing 2D array by 0 values
    lcsl = [[0 for i in range(n+2)] for j in range(m+2)]
    lcsr = [[0 for i in range(n+2)] for j in range(m+2)]
 
    # Filling LCS array for prefix substrings
    for i in range(1, m+1, 1):
        for j in range(1, n+1,1):
            if (str1[i-1] == str2[j-1]):
                lcsl[i][j] = 1 + lcsl[i-1][j-1]
            else:
                lcsl[i][j] = max(lcsl[i-1][j],
                                lcsl[i][j-1])
 
    # Filling LCS array for suffix substrings
    for i in range(m, 0, -1):
        for j in range(n, 0, -1):
            if (str1[i-1] == str2[j-1]):
                lcsr[i][j] = 1 + lcsr[i+1][j+1]
            else:
                lcsr[i][j] = max(lcsr[i+1][j],
                                lcsr[i][j+1])
 
        # Looping for all possible insertion positions
        # in first string
    ways = 0
    for i in range(0, m+1,1):
        # Trying all possible lower case characters
        for C in range(0, 26,1):
            # Now for each character, loop over same
            # character positions in second string
            for j in range(0, len(position[C]),1):
                p = position[C][j]
 
                # If both, left and right substrings make
                # total LCS then increase result by 1
                if (lcsl[i][p-1] + lcsr[i+1][p+1] == lcsl[m][n]):
                    ways += 1
    return ways
 
 
# Driver code to test above methods
str1 = "abcabc"
str2 = "abcd"
print(waysToIncreaseLCSBy1(str1, str2))
 
# This code is contributed by ankush_953


C#




// C# program to get number of ways
// to increase LCS by 1
using System;
using System.Collections.Generic;
 
class GFG{
     
static int M = 26;
 
// Method returns total ways to increase
// LCS length by 1
static int waysToIncreaseLCSBy1(String str1,
                                String str2)
{
    int m = str1.Length, n = str2.Length;
 
    // Fill positions of each character in vector
    List<int>[] position = new List<int>[M];
    for(int i = 0; i < M; i++)
        position[i] = new List<int>();
 
    for(int i = 1; i <= n; i++)
        position[str2[i - 1] - 'a'].Add(i);
 
    int[,] lcsl = new int[m + 2, n + 2];
    int[,] lcsr = new int[m + 2, n + 2];
 
    // Initializing 2D array by 0 values
    for(int i = 0; i <= m + 1; i++)
        for(int j = 0; j <= n + 1; j++)
            lcsl[i, j] = lcsr[i, j] = 0;
 
    // Filling LCS array for prefix substrings
    for(int i = 1; i <= m; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            if (str1[i - 1] == str2[j - 1])
                lcsl[i, j] = 1 + lcsl[i - 1, j - 1];
            else
                lcsl[i, j] = Math.Max(lcsl[i - 1, j],
                                      lcsl[i, j - 1]);
        }
    }
 
    // Filling LCS array for suffix substrings
    for(int i = m; i >= 1; i--)
    {
        for(int j = n; j >= 1; j--)
        {
            if (str1[i - 1] == str2[j - 1])
                lcsr[i, j] = 1 + lcsr[i + 1, j + 1];
            else
                lcsr[i, j] = Math.Max(lcsr[i + 1, j],
                                      lcsr[i, j + 1]);
        }
    }
 
    // Looping for all possible insertion
    // positions in first string
    int ways = 0;
    for(int i = 0; i <= m; i++)
    {
         
        // Trying all possible lower
        // case characters
        for(int d = 0; d < 26; d++)
        {
             
            // Now for each character, loop over same
            // character positions in second string
            for(int j = 0; j < position[d].Count; j++)
            {
                int p = position[d][j];
 
                // If both, left and right substrings make
                // total LCS then increase result by 1
                if (lcsl[i, p - 1] +
                    lcsr[i + 1, p + 1] == lcsl[m, n])
                    ways++;
            }
        }
    }
    return ways;
}
 
// Driver Code
public static void Main(String[] args)
{
    String str1 = "abcabc";
    String str2 = "abcd";
     
    Console.WriteLine(waysToIncreaseLCSBy1(str1, str2));
}
}
 
// This code is contributed by Princi Singh


Javascript




<script>
 
// JavaScript program to get number of ways to increase
// LCS by 1
let M = 26
 
// Method returns total ways to increase LCS length by 1
function waysToIncreaseLCSBy1(str1, str2)
{
    let m = str1.length;
    let n = str2.length;
 
    // Fill positions of each character in vector
    // vector<int> position[M];
    let position = new Array(M);
    for(let i = 0; i < M; i++)
        position[i] = [];
    for(let i = 1; i < n + 1; i++)
    {
        position[str2.charCodeAt(i-1)-97].push(i)
    }
 
    // Initializing 2D array by 0 values
    let lcsl = new Array(m+2);
    for(let i = 0; i < m + 2; i++)
    {
        lcsl[i] = new Array(n+2).fill(0);
    }
    let lcsr = new Array(m + 2);
    for(let i = 0; i < m + 2; i++)
    {
        lcsr[i] = new Array(n+2).fill(0);
    }
 
    // Filling LCS array for prefix substrings
    for(let i = 1; i < m + 1; i++)
    {
        for(let j = 1; j < n + 1; j++)
        {
            if (str1[i-1] == str2[j-1])
                lcsl[i][j] = 1 + lcsl[i-1][j-1]
            else
                lcsl[i][j] = Math.max(lcsl[i-1][j],
                                lcsl[i][j-1])
        }
    }
 
    // Filling LCS array for suffix substrings
    for(let i = m; i > 0; i--)
    {
        for(let j = n; j > 0; j--)
        {
            if (str1[i-1] == str2[j-1])
                lcsr[i][j] = 1 + lcsr[i+1][j+1]
            else
                lcsr[i][j] = Math.max(lcsr[i+1][j],
                                lcsr[i][j+1])
        }
    }
 
        // Looping for all possible insertion positions
        // in first string
    let ways = 0
    for(let i = 0; i < m + 1; i++)
    {
        // Trying all possible lower case characters
        for(let C = 0; C < 26; C++)
        {
         
            // Now for each character, loop over same
            // character positions in second string
            for(let j = 0; j < position[C].length; j++)
            {
                let p = position[C][j]
 
                // If both, left and right substrings make
                // total LCS then increase result by 1
                if (lcsl[i][p-1] + lcsr[i+1][p+1] == lcsl[m][n])
                    ways += 1
            }
        }
    }
    return ways
}
 
// Driver code to test above methods
let str1 = "abcabc"
let str2 = "abcd"
document.write(waysToIncreaseLCSBy1(str1, str2))
 
// This code is contributed by shinjanpatra
 
</script>


Output

4

Time Complexity : O(mn) 
Auxiliary Space : O(mn)

This article is contributed by Utkarsh Trivedi. If you like neveropen and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the neveropen main page and help other Geeks. 

Feeling lost in the world of random DSA topics, wasting time without progress? It’s time for a change! Join our DSA course, where we’ll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!

RELATED ARTICLES

Most Popular

Recent Comments