📜  将不重复出现算作子序列

📅  最后修改于: 2021-04-24 18:17:40             🧑  作者: 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,因为没有字符串可以是空字符串。

    递归情况:

    1. 如果ST的最后一个字符不匹配,则删除S的最后一个字符并再次调用递归函数。因为S的最后一个字符不能成为子序列的一部分,或将其删除并检查其他字符。
    2. 如果S的最后一个字符匹配,则可能有两种可能性,第一个可能是子序列,其中S的最后一个字符是它的一部分,其次是它不是子序列的一部分。因此,所需值将是两者之和。调用递归函数一次,删除两个字符串的最后一个字符,然后再次调用,只删除S的最后一个字符。


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

算法:

  1. 创建2D数组mat [m + 1] [n + 1] ,其中m是字符串T的长度,n是字符串S的长度。mat [i] [j]表示子字符串S(1。)的不同子序列数。 i)和子字符串T(1..j),因此mat [m] [n]包含我们的解决方案。
  2. 用全0初始化第一列。空字符串不能包含其他字符串作为后继序列
  3. 用全1初始化第一行。空字符串是全部的子序列。
  4. 以自下而上的方式填充矩阵,即,首先计算当前字符串的所有子问题。
  5. 从头到尾遍历字符串T。 (计数器是)
  6. 对于外循环的每次迭代,从头到尾遍历字符串S。 (计数器为j )
  7. 如果在字符串T匹配的与第j个字符串S的字符个索引的字符时,获得的值考虑两种情况。首先,是所有不处于S最后一个字符的子串和第二个是没有两个,即,最后一个字符的子串[I + 1] [j] +垫[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


输出:

6

复杂度分析:

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