给定两个字符串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 的长度。这个问题可以递归定义如下。
- 给定字符串T是一个空字符串,返回 1 作为空字符串可以是所有的子序列。
- 给定字符串S是一个空字符串,返回 0 因为没有字符串可以是空字符串。
- 如果S和T的最后一个字符不匹配,则删除S的最后一个字符并再次调用递归函数。因为 S 的最后一个字符不能是子序列的一部分或删除它并检查其他字符。
- 如果S的最后一个字符匹配,那么可能有两种可能性,第一种可能是S的最后一个字符是它的一部分的子序列,第二种是它不是子序列的一部分。所以所需的值将是两者的总和。既去掉字符串的最后一个字符用S的只有最后一个字符调用递归函数一次又一次删除。
蓝色圆角矩形代表接受状态或存在子序列,红色圆角矩形代表无法形成子序列。
由于上述递归结果中存在重叠子问题,可以应用动态规划方法解决上述问题。将子问题存储在 Hashmap 或数组中,并在再次调用该函数时返回该值。
算法:
- 创建一个二维数组mat[m+1][n+1] ,其中 m 是字符串T 的长度,n 是字符串S 的长度。 mat[i][j] 表示子字符串 S(1.. i) 和子串 T(1..j) 所以 mat[m][n] 包含我们的解决方案。
- 用全 0 初始化第一列。空字符串不能有另一个字符串作为 suhsequence
- 用全 1 初始化第一行。空字符串是所有字符串的子序列。
- 自底向上填充矩阵,即先计算当前字符串的所有子问题。
- 从头到尾遍历字符串T。 (计数器是i )
- 对于外循环的每次迭代,从头到尾遍历字符串S。 (计数器是j )
- 如果在我字符串T匹配的与第j个字符串S的字符个索引的字符时,获得的值考虑两种情况。首先,是 S 中没有最后一个字符的所有子字符串,第二个是两个都没有最后一个字符的子字符串,即mat[i+1][j] + mat[i][j] 。
- 否则即使删除了S 的第j个字符,值也会相同,即 mat[i+1][j]
- 打印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 现场工作专业课程和学生竞争性编程现场课程。