📌  相关文章
📜  将不同的出现计数为子序列

📅  最后修改于: 2021-09-17 06:46:54             🧑  作者: Mango

给定两个字符串S 和 T,找出 S 中作为子序列的 T 不同出现的次数。
例子:

Input: S = banana, T = ban
Output: 3
Explanation: T appears in S as below three subsequences.
[ban], [ba  n], [b   an]

Input: S = geeksforgeeks, T = ge
Output: 6
Explanation: T appears in S as below three subsequences.
[ge], [     ge], [g e], [g    e] [g     e]
and [     g e]      

方法:创建一个递归函数,使其返回与T匹配的S 子序列的计数。这里 m 是 T 的长度,n 是 S 的长度。这个问题可以递归定义如下。

  1. 给定字符串T是一个空字符串,返回 1 作为空字符串可以是所有的子序列。
  2. 给定字符串S是一个空字符串,返回 0 因为没有字符串可以是空字符串。
  3. 如果ST的最后一个字符不匹配,则删除S的最后一个字符并再次调用递归函数。因为 S 的最后一个字符不能是子序列的一部分或删除它并检查其他字符。
  4. 如果S的最后一个字符匹配,那么可能有两种可能性,第一种可能是S的最后一个字符是它的一部分的子序列,第二种是它不是子序列的一部分。所以所需的值将是两者的总和。既去掉字符串的最后一个字符用S的只有最后一个字符调用递归函数一次又一次删除。

蓝色圆角矩形代表接受状态或存在子序列,红色圆角矩形代表无法形成子序列。
由于上述递归结果中存在重叠子问题,可以应用动态规划方法解决上述问题。将子问题存储在 Hashmap 或数组中,并在再次调用该函数时返回该值。
算法:

  1. 创建一个二维数组mat[m+1][n+1] ,其中 m 是字符串T 的长度,n 是字符串S 的长度。 mat[i][j] 表示子字符串 S(1.. i) 和子串 T(1..j) 所以 mat[m][n] 包含我们的解决方案。
  2. 用全 0 初始化第一列。空字符串不能有另一个字符串作为 suhsequence
  3. 用全 1 初始化第一行。空字符串是所有字符串的子序列。
  4. 自底向上填充矩阵,即先计算当前字符串的所有子问题。
  5. 从头到尾遍历字符串T。 (计数器是i )
  6. 对于外循环的每次迭代,从头到尾遍历字符串S。 (计数器是j )
  7. 如果在字符串T匹配的与第j个字符串S的字符个索引的字符时,获得的值考虑两种情况。首先,是 S 中没有最后一个字符的所有子字符串,第二个是两个都没有最后一个字符的子字符串,即mat[i+1][j] + mat[i][j]
  8. 否则即使删除了S 的j个字符,值也会相同,即 mat[i+1][j]
  9. 打印mat[m-1][n-1] 的值作为答案。
C++
/* C/C++ program to count number of times S appears
   as a subsequence in T */
#include 
using namespace std;
 
int findSubsequenceCount(string S, string T)
{
    int m = T.length(), n = S.length();
 
    // T can't appear as a subsequence in S
    if (m > n)
        return 0;
 
    // mat[i][j] stores the count of occurrences of
    // T(1..i) in S(1..j).
    int mat[m + 1][n + 1];
 
    // Initializing first column with all 0s. An empty
    // string can't have another string as suhsequence
    for (int i = 1; i <= m; i++)
        mat[i][0] = 0;
 
    // Initializing first row with all 1s. An empty
    // string is subsequence of all.
    for (int j = 0; j <= n; j++)
        mat[0][j] = 1;
 
    // Fill mat[][] in bottom up manner
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
 
            // If last characters don't match, then value
            // is same as the value without last character
            // in S.
            if (T[i - 1] != S[j - 1])
                mat[i][j] = mat[i][j - 1];
 
            // Else value is obtained considering two cases.
            // a) All substrings without last character in S
            // b) All substrings without last characters in
            // both.
            else
                mat[i][j] = mat[i][j - 1] + mat[i - 1][j - 1];
        }
    }
 
    /* uncomment this to print matrix mat
    for (int i = 1; i <= m; i++, cout << endl)
        for (int j = 1; j <= n; j++)
            cout << mat[i][j] << " ";  */
    return mat[m][n];
}
 
// Driver code to check above method
int main()
{
    string T = "ge";
    string S = "geeksforgeeks";
    cout << findSubsequenceCount(S, T) << endl;
    return 0;
}


Java
// Java program to count number of times
// S appears as a subsequence in T
import java.io.*;
 
class GFG {
    static int findSubsequenceCount(String S, String T)
    {
        int m = T.length();
        int n = S.length();
 
        // T can't appear as a subsequence in S
        if (m > n)
            return 0;
 
        // mat[i][j] stores the count of
        // occurrences of T(1..i) in S(1..j).
        int mat[][] = new int[m + 1][n + 1];
 
        // Initializing first column with
        // all 0s. An emptystring can't have
        // another string as suhsequence
        for (int i = 1; i <= m; i++)
            mat[i][0] = 0;
 
        // Initializing first row with all 1s.
        // An empty string is subsequence of all.
        for (int j = 0; j <= n; j++)
            mat[0][j] = 1;
 
        // Fill mat[][] in bottom up manner
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                // If last characters don't match,
                // then value is same as the value
                // without last character in S.
                if (T.charAt(i - 1) != S.charAt(j - 1))
                    mat[i][j] = mat[i][j - 1];
 
                // Else value is obtained considering two cases.
                // a) All substrings without last character in S
                // b) All substrings without last characters in
                // both.
                else
                    mat[i][j] = mat[i][j - 1] + mat[i - 1][j - 1];
            }
        }
 
        /* uncomment this to print matrix mat
        for (int i = 1; i <= m; i++, cout << endl)
            for (int j = 1; j <= n; j++)
                System.out.println ( mat[i][j] +" "); */
        return mat[m][n];
    }
 
    // Driver code to check above method
    public static void main(String[] args)
    {
        String T = "ge";
        String S = "geeksforgeeks";
        System.out.println(findSubsequenceCount(S, T));
    }
}
// This code is contributed by vt_m


Python3
# Python3 program to count number of times
# S appears as a subsequence in T
def findSubsequenceCount(S, T):
 
    m = len(T)
    n = len(S)
 
    # T can't appear as a subsequence in S
    if m > n:
        return 0
 
    # mat[i][j] stores the count of
    # occurrences of T(1..i) in S(1..j).
    mat = [[0 for _ in range(n + 1)]
              for __ in range(m + 1)]
 
    # Initializing first column with all 0s. x
    # An empty string can't have another
    # string as suhsequence
    for i in range(1, m + 1):
        mat[i][0] = 0
 
    # Initializing first row with all 1s.
    # An empty string is subsequence of all.
    for j in range(n + 1):
        mat[0][j] = 1
 
    # Fill mat[][] in bottom up manner
    for i in range(1, m + 1):
        for j in range(1, n + 1):
 
            # If last characters don't match,
            # then value is same as the value
            # without last character in S.
            if T[i - 1] != S[j - 1]:
                mat[i][j] = mat[i][j - 1]
                 
            # Else value is obtained considering two cases.
            # a) All substrings without last character in S
            # b) All substrings without last characters in
            # both.
            else:
                mat[i][j] = (mat[i][j - 1] +
                             mat[i - 1][j - 1])
 
    return mat[m][n]
 
# Driver Code
if __name__ == "__main__":
    T = "ge"
    S = "geeksforgeeks"
    print(findSubsequenceCount(S, T))
 
# This code is contributed
# by vibhu4agarwal


C#
// C# program to count number of times
// S appears as a subsequence in T
using System;
 
class GFG {
 
    static int findSubsequenceCount(string S, string T)
    {
        int m = T.Length;
        int n = S.Length;
 
        // T can't appear as a subsequence in S
        if (m > n)
            return 0;
 
        // mat[i][j] stores the count of
        // occurrences of T(1..i) in S(1..j).
        int[, ] mat = new int[m + 1, n + 1];
 
        // Initializing first column with
        // all 0s. An emptystring can't have
        // another string as suhsequence
        for (int i = 1; i <= m; i++)
            mat[i, 0] = 0;
 
        // Initializing first row with all 1s.
        // An empty string is subsequence of all.
        for (int j = 0; j <= n; j++)
            mat[0, j] = 1;
 
        // Fill mat[][] in bottom up manner
        for (int i = 1; i <= m; i++) {
 
            for (int j = 1; j <= n; j++) {
 
                // If last characters don't match,
                // then value is same as the value
                // without last character in S.
                if (T[i - 1] != S[j - 1])
                    mat[i, j] = mat[i, j - 1];
 
                // Else value is obtained considering two cases.
                // a) All substrings without last character in S
                // b) All substrings without last characters in
                // both.
                else
                    mat[i, j] = mat[i, j - 1] + mat[i - 1, j - 1];
            }
        }
 
        /* uncomment this to print matrix mat
        for (int i = 1; i <= m; i++, cout << endl)
            for (int j = 1; j <= n; j++)
                System.out.println ( mat[i][j] +" "); */
        return mat[m, n];
    }
 
    // Driver code to check above method
    public static void Main()
    {
        string T = "ge";
        string S = "geeksforgeeks";
        Console.WriteLine(findSubsequenceCount(S, T));
    }
}
 
// This code is contributed by vt_m


PHP
 $n)
        return 0;
 
    // mat[i][j] stores the count of
    // occurrences of T(1..i) in S(1..j).
    $mat = array(array());
 
    // Initializing first column with all 0s.
    // An empty string can't have another
    // string as suhsequence
    for ($i = 1; $i <= $m; $i++)
        $mat[$i][0] = 0;
 
    // Initializing first row with all 1s.
    // An empty string is subsequence of all.
    for ($j = 0; $j <= $n; $j++)
        $mat[0][$j] = 1;
 
    // Fill mat[][] in bottom up manner
    for ($i = 1; $i <= $m; $i++)
    {
        for ($j = 1; $j <= $n; $j++)
        {
            // If last characters don't match,
            // then value is same as the value
            // without last character in S.
            if ($T[$i - 1] != $S[$j - 1])
                $mat[$i][$j] = $mat[$i][$j - 1];
 
            // Else value is obtained considering two cases.
            // a) All substrings without last character in S
            // b) All substrings without last characters in
            // both.
            else
                $mat[$i][$j] = $mat[$i][$j - 1] +
                               $mat[$i - 1][$j - 1];
        }
    }
 
    /* uncomment this to print matrix mat
    for (int i = 1; i <= m; i++, cout << endl)
        for (int j = 1; j <= n; j++)
            cout << mat[i][j] << " "; */
    return $mat[$m][$n];
}
 
// Driver Code
$T = "ge";
$S = "geeksforgeeks";
echo findSubsequenceCount($S, $T) . "\n";
 
// This code is contributed
// by Akanksha Rai


Javascript


输出:

6

复杂度分析:

  • 时间复杂度: O(m*n)。
    只需要遍历一次矩阵,所以时间Complexity为O(m*n)
  • 辅助空间: O(m*n)。
    需要一个大小为 m*n 的矩阵,因此空间复杂度为 O(m*n)。
    注意:由于 mat[i][j] 只访问当前行和上一行的元素,我们可以通过使用两行仅将空间从 m*n 减少到 2*n 来优化辅助空间。

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程