📜  计算将两个字符串的LCS长度加一的方法

📅  最后修改于: 2021-04-29 17:16:20             🧑  作者: Mango

鉴于较低的字母字符两个字符串,我们需要找到办法的号码中插入第一个字符串中的字符,使得由一个两个字符串增加LCS的长度。

例子:

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

这个想法是尝试在第一个字符串的每个位置上所有26个可能的字符,如果str1的长度是m,那么可以在(m + 1)个位置插入一个新字符,现在假设在任何时候将字符c插入在str1的第i个位置那么我们将其与str2中所有具有字符c的位置进行匹配。假设一个这样的位置是j,那么对于LCS的总长度要比以前大一倍,以下条件应满足,

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

上式表示,插入字符的后缀和前缀子字符串的LCS的总和必须与字符串的总LCS相同,因此,当在第一个字符串插入相同的字符时,它将使LCS的长度增加一。
在下面的代码中,两个二维数组lcsl和lcsr用于分别存储字符串的前缀和后缀的LCS。可以在此处找到填充这些2D阵列的方法。

请参阅下面的代码以更好地理解,

C++
// C++ program to get number of ways to increase
// LCS by 1
#include 
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 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


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[] 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 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[] position = new List[M];
    for(int i = 0; i < M; i++)
        position[i] = new List();
 
    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


输出:

4

时间复杂度: O(mn)
辅助空间: O(mn)