Find number of times a string occurs as a subsequence in given string
Last Updated :
17 Apr, 2023
Given two strings, find the number of times the second string occurs in the first string, whether continuous or discontinuous.
Examples:
Input:
string a = "GeeksforGeeks"
string b = "Gks"
Output: 4
Explanation:
The four strings are - (Check characters marked in bold)
GeeksforGeeks
GeeksforGeeks
GeeksforGeeks
GeeksforGeeks
If we carefully analyze the given problem, we can see that it can be easily divided into sub-problems. The idea is to process all characters of both strings one by one starting from either from left or right side. Let us traverse from right corner, there are two possibilities for every pair of character being traversed.
m: Length of str1 (first string)
n: Length of str2 (second string)
If last characters of two strings are same,
1. We consider last characters and get count for remaining
strings. So we recur for lengths m-1 and n-1.
2. We can ignore last character of first string and
recurse for lengths m-1 and n.
else
If last characters are not same,
We ignore last character of first string and
recurse for lengths m-1 and n.
Below is the implementation of above Naive recursive solution –
C++
#include <iostream>
using namespace std;
int count(string a, string b, int m, int n)
{
if ((m == 0 && n == 0) || n == 0)
return 1;
if (m == 0)
return 0;
if (a[m - 1] == b[n - 1])
return count(a, b, m - 1, n - 1) +
count(a, b, m - 1, n);
else
return count(a, b, m - 1, n);
}
int main()
{
string a = "GeeksforGeeks" ;
string b = "Gks" ;
cout << count(a, b, a.size(), b.size()) << endl;
return 0;
}
|
Java
import java.io.*;
class GFG
{
static int count(String a, String b, int m, int n)
{
if ((m == 0 && n == 0 ) || n == 0 )
return 1 ;
if (m == 0 )
return 0 ;
if (a.charAt(m - 1 ) == b.charAt(n - 1 ))
return count(a, b, m - 1 , n - 1 ) +
count(a, b, m - 1 , n);
else
return count(a, b, m - 1 , n);
}
public static void main (String[] args)
{
String a = "GeeksforGeeks" ;
String b = "Gks" ;
System.out.println( count(a, b, a.length(), b.length())) ;
}
}
|
Python 3
def count(a, b, m, n):
if ((m = = 0 and n = = 0 ) or n = = 0 ):
return 1
if (m = = 0 ):
return 0
if (a[m - 1 ] = = b[n - 1 ]):
return (count(a, b, m - 1 , n - 1 ) +
count(a, b, m - 1 , n))
else :
return count(a, b, m - 1 , n)
a = "GeeksforGeeks"
b = "Gks"
print (count(a, b, len (a), len (b)))
|
C#
using System;
class GFG
{
static int count( string a, string b, int m, int n)
{
if ((m == 0 && n == 0) || n == 0)
return 1;
if (m == 0)
return 0;
if (a[m - 1] == b[n - 1])
return count(a, b, m - 1, n - 1) +
count(a, b, m - 1, n);
else
return count(a, b, m - 1, n);
}
public static void Main ()
{
string a = "GeeksforGeeks" ;
string b = "Gks" ;
Console.Write( count(a, b, a.Length, b.Length) );
}
}
|
PHP
<?php
function count_1( $a , $b , $m , $n )
{
if (( $m == 0 && $n == 0) || $n == 0)
return 1;
if ( $m == 0)
return 0;
if ( $a [ $m - 1] == $b [ $n - 1])
return count_1( $a , $b , $m - 1, $n - 1) +
count_1( $a , $b , $m - 1, $n );
else
return count_1( $a , $b , $m - 1, $n );
}
$a = "GeeksforGeeks" ;
$b = "Gks" ;
echo count_1( $a , $b , strlen ( $a ), strlen ( $b )) . "\n" ;
return 0;
?>
|
Javascript
<script>
function count( a, b , m , n)
{
if ((m == 0 && n == 0) || n == 0)
return 1;
if (m == 0)
return 0;
if (a[m - 1] == b[n - 1])
return count(a, b, m - 1, n - 1) + count(a, b, m - 1, n);
else
return count(a, b, m - 1, n);
}
var a = "GeeksforGeeks" ;
var b = "Gks" ;
document.write(count(a, b, a.length, b.length));
</script>
|
The time complexity of above solution is exponential. If we carefully analyze, we can see that many sub-problems are solved again and again. Since same sub-problems are called again, this problem has Overlapping sub-problems property. So the problem has both properties (see this and this) of a dynamic programming problem. Like other typical Dynamic Programming problems, re-computations of same sub-problems can be avoided by constructing a temporary array that stores results of sub-problems.
Space Complexity: O(n)
We can solve it in 2 ways
1) Top-down DP
We can extend the recursion solution and stores the states of dp in 2d vector so that we don’t recompute the sub problems again.
C++
#include <bits/stdc++.h>
using namespace std;
int count(string a, string b, int m, int n,
vector<vector< int > >& dp)
{
if ((m == 0 && n == 0) || n == 0)
return 1;
if (m == 0)
return 0;
if (dp[m][n] != -1) {
return dp[m][n];
}
if (a[m - 1] == b[n - 1])
return dp[m][n] = count(a, b, m - 1, n - 1, dp)
+ count(a, b, m - 1, n, dp);
else
return dp[m][n] = count(a, b, m - 1, n, dp);
}
int main()
{
string a = "GeeksforGeeks" ;
string b = "Gks" ;
vector<vector< int > > dp(a.size() + 1,
vector< int >(b.size() + 1, -1));
cout << count(a, b, a.size(), b.size(), dp) << endl;
return 0;
}
|
Java
import java.util.Arrays;
public class Main
{
public static int count(String a, String b, int m, int n,
int [][] dp)
{
if ((m == 0 && n == 0 ) || n == 0 )
return 1 ;
if (m == 0 )
return 0 ;
if (dp[m][n] != - 1 ) {
return dp[m][n];
}
if (a.charAt(m - 1 ) == b.charAt(n - 1 ))
return dp[m][n] = count(a, b, m - 1 , n - 1 , dp)
+ count(a, b, m - 1 , n, dp);
else
return dp[m][n] = count(a, b, m - 1 , n, dp);
}
public static void main(String[] args) {
String a = "GeeksforGeeks" ;
String b = "Gks" ;
int [][] dp = new int [a.length() + 1 ][b.length() + 1 ];
for ( int [] row : dp)
Arrays.fill(row, - 1 );
System.out.println(count(a, b, a.length(), b.length(), dp));
}
}
|
Python3
def count(a: str , b: str , m: int , n: int , dp: list ) - > int :
if (m = = 0 and n = = 0 ) or n = = 0 :
return 1
if m = = 0 :
return 0
if dp[m][n] ! = - 1 :
return dp[m][n]
if a[m - 1 ] = = b[n - 1 ]:
dp[m][n] = count(a, b, m - 1 , n - 1 , dp) + count(a, b, m - 1 , n, dp)
else :
dp[m][n] = count(a, b, m - 1 , n, dp)
return dp[m][n]
a = "GeeksforGeeks"
b = "Gks"
dp = [[ - 1 ] * ( len (b) + 1 ) for _ in range ( len (a) + 1 )]
print (count(a, b, len (a), len (b), dp))
|
C#
using System;
public class GFG
{
public static int Count( string a, string b, int m, int n, int [,] dp)
{
if ((m == 0 && n == 0) || n == 0)
return 1;
if (m == 0)
return 0;
if (dp[m, n] != -1)
{
return dp[m, n];
}
if (a[m - 1] == b[n - 1])
return dp[m, n] = Count(a, b, m - 1, n - 1, dp) + Count(a, b, m - 1, n, dp);
else
return dp[m, n] = Count(a, b, m - 1, n, dp);
}
public static void Main()
{
string a = "GeeksforGeeks" ;
string b = "Gks" ;
int [,] dp = new int [a.Length + 1, b.Length + 1];
for ( int i = 0; i <= a.Length; i++)
{
for ( int j = 0; j <= b.Length; j++)
{
dp[i, j] = -1;
}
}
Console.WriteLine(Count(a, b, a.Length, b.Length, dp));
}
}
|
Javascript
function count(a, b, m, n, dp) {
if ((m == 0 && n == 0) || n == 0) {
return 1;
}
if (m == 0) {
return 0;
}
if (dp[m][n] != -1) {
return dp[m][n];
}
if (a[m - 1] === b[n - 1]) {
return (dp[m][n] =
count(a, b, m - 1, n - 1, dp) +
count(a, b, m - 1, n, dp)
);
} else {
return (dp[m][n] = count(a, b, m - 1, n, dp));
}
}
const a = "GeeksforGeeks" ;
const b = "Gks" ;
const dp = Array.from({
length: a.length + 1
}, () =>
Array(b.length + 1).fill(-1)
);
console.log(count(a, b, a.length, b.length, dp));
|
Time complexity of above solutions is O(MN) excluding recursion stack space.
Auxiliary space used by the program is O(MN).
2) Bottom-Up DP
Below is its implementation using Dynamic Programming –
C++
#include <iostream>
using namespace std;
int count(string a, string b)
{
int m = a.length();
int n = b.length();
int lookup[m + 1][n + 1] = { { 0 } };
for ( int i = 0; i <= n; ++i)
lookup[0][i] = 0;
for ( int i = 0; i <= m; ++i)
lookup[i][0] = 1;
for ( int i = 1; i <= m; i++)
{
for ( int j = 1; j <= n; j++)
{
if (a[i - 1] == b[j - 1])
lookup[i][j] = lookup[i - 1][j - 1] +
lookup[i - 1][j];
else
lookup[i][j] = lookup[i - 1][j];
}
}
return lookup[m][n];
}
int main()
{
string a = "GeeksforGeeks" ;
string b = "Gks" ;
cout << count(a, b);
return 0;
}
|
Java
import java.io.*;
class GFG
{
static int count(String a, String b)
{
int m = a.length();
int n = b.length();
int lookup[][] = new int [m + 1 ][n + 1 ];
for ( int i = 0 ; i <= n; ++i)
lookup[ 0 ][i] = 0 ;
for ( int i = 0 ; i <= m; ++i)
lookup[i][ 0 ] = 1 ;
for ( int i = 1 ; i <= m; i++)
{
for ( int j = 1 ; j <= n; j++)
{
if (a.charAt(i - 1 ) == b.charAt(j - 1 ))
lookup[i][j] = lookup[i - 1 ][j - 1 ] +
lookup[i - 1 ][j];
else
lookup[i][j] = lookup[i - 1 ][j];
}
}
return lookup[m][n];
}
public static void main (String[] args)
{
String a = "GeeksforGeeks" ;
String b = "Gks" ;
System.out.println(count(a, b));
}
}
|
Python3
def count(a, b):
m = len (a)
n = len (b)
lookup = [[ 0 ] * (n + 1 ) for i in range (m + 1 )]
for i in range (n + 1 ):
lookup[ 0 ][i] = 0
for i in range (m + 1 ):
lookup[i][ 0 ] = 1
for i in range ( 1 , m + 1 ):
for j in range ( 1 , n + 1 ):
if a[i - 1 ] = = b[j - 1 ]:
lookup[i][j] = lookup[i - 1 ][j - 1 ] + lookup[i - 1 ][j]
else :
lookup[i][j] = lookup[i - 1 ][j]
return lookup[m][n]
if __name__ = = '__main__' :
a = "GeeksforGeeks"
b = "Gks"
print (count(a, b))
|
C#
using System;
class GFG
{
static int count(String a, String b)
{
int m = a.Length;
int n = b.Length;
int [,] lookup = new int [m + 1, n + 1];
for ( int i = 0; i <= n; ++i)
lookup[0, i] = 0;
for ( int i = 0; i <= m; ++i)
lookup[i, 0] = 1;
for ( int i = 1; i <= m; i++)
{
for ( int j = 1; j <= n; j++)
{
if (a[i - 1] == b[j - 1])
lookup[i, j] = lookup[i - 1, j - 1] +
lookup[i - 1, j];
else
lookup[i, j] = lookup[i - 1, j];
}
}
return lookup[m, n];
}
public static void Main()
{
String a = "GeeksforGeeks" ;
String b = "Gks" ;
Console.WriteLine(count(a, b));
}
}
|
PHP
<?php
function count1( $a , $b )
{
$m = strlen ( $a );
$n = strlen ( $b );
$lookup = array_fill (0, $m + 1, array_fill (0, $n + 1, 0));
for ( $i = 0; $i <= $m ; ++ $i )
$lookup [ $i ][0] = 1;
for ( $i = 1; $i <= $m ; $i ++)
{
for ( $j = 1; $j <= $n ; $j ++)
{
if ( $a [ $i - 1] == $b [ $j - 1])
$lookup [ $i ][ $j ] = $lookup [ $i - 1][ $j - 1] +
$lookup [ $i - 1][ $j ];
else
$lookup [ $i ][ $j ] = $lookup [ $i - 1][ $j ];
}
}
return $lookup [ $m ][ $n ];
}
$a = "GeeksforGeeks" ;
$b = "Gks" ;
echo count1( $a , $b );
?>
|
Javascript
<script>
function count(a, b)
{
var m = a.length;
var n = b.length;
var lookup = Array(m + 1);
for ( var i = 0; i < m + 1; i++)
lookup[i] = Array(n + 1).fill(0);
for (i = 0; i <= n; ++i)
lookup[0][i] = 0;
for (i = 0; i <= m; ++i)
lookup[i][0] = 1;
for (i = 1; i <= m; i++)
{
for (j = 1; j <= n; j++)
{
if (a.charAt(i - 1) == b.charAt(j - 1))
lookup[i][j] = lookup[i - 1][j - 1] +
lookup[i - 1][j];
else
lookup[i][j] = lookup[i - 1][j];
}
}
return lookup[m][n];
}
var a = "GeeksforGeeks" ;
var b = "Gks" ;
document.write(count(a, b));
</script>
|
Time complexity of above solutions is O(MN).
Auxiliary space used by the program is O(MN).
Another Method :
This method was contributed by Kunal Hotwani
We can solve this problem by considering the fact that, in the final subsequences that will be chosen in the count, the character at b[i] will always follow the character at b[i – 1] (by the definition of a subsequence).
Using this fact, we count the total number of occurrences of string b, using an array of size equal to the length of string b.
We can create an array of size equal to n (b.size()), the jth element in this array stores the number of subsequences in the string a which are equal to b[0]b[1]…b[j]. We will traverse the string a, each time updating all the values in this array. Let’s call this array count.
While traversing the string a, we will traverse the string b in reverse for each character of a, let’s say we are at the ith character of a (a[i]) and we start the reverse traversal of the b, if the jth character of b (b[j]) is equal to a[i], a[i] can be appended to all the subsequences of a (traversed until now) which are equal to b[0]b[1]…b[j – 1] (number of these type of subsequences is stored in count[j -1]), making subsequences equal to b[0]b[1]…b[j] (number of these type of subsequences is stored in count[j]), thus count[j] can be increased by count[j – 1], when we encounter a character in string b which is equal to a[i].
NOTE : When j is equal to 0, the character a[i] cannot be appended to any subsequences, instead it can start a new subsequence equal to b[0], thus when a[i] is equal to b[0], we increase count[0] by 1 (As it stores the count all the subsequences of type b[0]).
Thus, in this method we are counting all the subsequences of a type b[0]b[1]…b[j] that can created using a particular character of a, a[i].
Finally, after traversing the complete string a, the final answer will be stored in count[n – 1], as we require the number of subsequences of type b[0]b[1]…b[n – 1].
The reason for traversal of b in reverse
Let us consider b = geeks, we will create the count array of size 5 and start the traversal of b string from front for each a[i].
When a[i] = ‘e’, we will first increase count[1](representing the first e in string b) by count[0], and then increase count[2](representing the second e in string b) by count[1], this not ideal because we always the need the value of count[j – 1] to represent the number of subsequences of type b[0]b[1]…b[j – 1] in the string a[0]a[1]…a[i – 1] as we cannot use the same ‘e’ twice in one subsequence (In this case count[1] will represent a[i] appended to all the subsequences of type b[0] and using this count[1] to update count[2] which will mean we use the same ‘e’ twice).
Below is the code for this approach
C++
#include <bits/stdc++.h>
using namespace std;
int countWays(string S1, string S2)
{
int m = S1.size(), n = S2.size();
vector< int > count(n, 0);
for ( int i = 0; i < m; i++)
{
for ( int j = n - 1; j >= 0; j--)
{
if (S1[i] == S2[j])
{
count[j] += (j == 0 ? 1 : count[j - 1]);
}
}
}
return count[n - 1];
}
int main()
{
string S1 = "geeksforgeeks" , S2 = "geeks" ;
cout << countWays(S1, S2) << "\n" ;
return 0;
}
|
Java
import java.util.*;
class GFG {
public static int countWays(String s1, String s2)
{
int m = s1.length(), n = s2.length();
int [] count = new int [n];
for ( int i = 0 ; i < m; i++) {
for ( int j = n - 1 ; j >= 0 ; j--) {
if (s1.charAt(i) == s2.charAt(j)) {
count[j] += (j == 0 ? 1 : count[j - 1 ]);
}
}
}
return count[n - 1 ];
}
public static void main(String[] args)
{
String s1 = "geeksforgeeks" , s2 = "geeks" ;
System.out.println(countWays(s1, s2));
}
}
|
Python3
def countWays(S1, S2):
m = len (S1)
n = len (S2)
count = [ 0 ] * n
for i in range (m):
for j in range (n - 1 , - 1 , - 1 ):
if S1[i] = = S2[j]:
count[j] + = count[j - 1 ] if j ! = 0 else 1
return count[n - 1 ]
S1 = "geeksforgeeks"
S2 = "geeks"
print (countWays(S1, S2))
|
C#
using System;
public class GFG {
static int countWays( string S1, string S2)
{
int m = S1.Length, n = S2.Length;
int [] count = new int [n];
for ( int i = 0; i < m; i++)
{
for ( int j = n - 1; j >= 0; j--)
{
if (S1[i] == S2[j]) {
count[j] += (j == 0 ? 1 : count[j - 1]);
}
}
}
return count[n - 1];
}
static void Main( string [] args)
{
string S1 = "geeksforgeeks" , S2 = "geeks" ;
Console.WriteLine(countWays(S1, S2));
}
}
|
Javascript
function countWays(s1, s2) {
const m = s1.length,
n = s2.length;
const count = new Array(n).fill(0);
for (let i = 0; i < m; i++) {
for (let j = n - 1; j >= 0; j--) {
if (s1.charAt(i) == s2.charAt(j)) {
count[j] += (j == 0 ? 1 : count[j - 1]);
}
}
}
return count[n - 1];
}
const s1 = "geeksforgeeks" ,
s2 = "geeks" ;
console.log(countWays(s1, s2));
|
Time complexity of above solutions is O(MN).
Auxiliary space used by the program is O(N).
If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.GeeksforGeeks.org or mail your article to contribute@GeeksforGeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.
Share your thoughts in the comments
Please Login to comment...