Given two strings pat and txt, where pat is always shorter than txt, count the distinct occurrences of pat as a subsequence in txt.
Examples:
Input: txt = abba, pat = aba
Output: 2
Explanation: pat appears in txt as below two subsequences.
[abba], [abba]Input: txt = banana, pat = ban
Output: 3
Explanation: pat appears in txt as below three subsequences.
[banana], [banana], [banana]
Input: txt = geeks, pat = ge
Output: 2
Explanation: pat appears in txt as below two subsequences.
[geeks], [geeks]
Table of Content
[Naive Approach ] Using Recursion - O(2^n) Time and O(n) Space
If we match the current character in the pattern with the current character in the text, we have two options:
- We can either include this character and move to the next character in both the pattern and the text,
- Or we can skip the current character in the text and try to match the same character in the pattern with the next character in the text.
This leads to the following recursive relationship:
1. If the characters match (i.e., txt[i-1] == pat[j-1]), the count of distinct subsequences can be expressed as the sum of:
- The count of subsequences by including this character from both txt and pat (subCountRec(i-1, j-1, txt, pat)).
- The count of subsequences by excluding the character from txt (subCountRec(i-1, j, txt, pat)).
2. If the characters do not match, we can only exclude the character from txt, which gives us:
- The count of subsequences without considering the current character in txt (subCountRec(i-1, j, txt, pat)).
#include <iostream>
#include <string>
using namespace std;
int subCountRec(int i, int j, string &txt, string &pat)
{
if (j == 0)
{
// Empty pattern is found in
// all suffixes
return 1;
}
if (i == 0)
{
// No more characters in
// txt to match pat
return 0;
}
if (txt[i - 1] == pat[j - 1])
{
// Count both cases
return subCountRec(i - 1, j - 1, txt, pat) + subCountRec(i - 1, j, txt, pat);
}
return subCountRec(i - 1, j, txt, pat);
}
int subseqCount(string &txt, string &pat)
{
return subCountRec(txt.size(), pat.size(), txt, pat);
}
int main()
{
string pat = "aba";
string txt = "abba";
cout << subseqCount(txt, pat) << endl;
return 0;
}
public class GfG {
static int subCountRec(int i, int j, String txt, String pat) {
if (j == 0) {
// Empty pattern is found in
// all suffixes
return 1;
}
if (i == 0) {
// No more characters in
// txt to match pat
return 0;
}
if (txt.charAt(i - 1) == pat.charAt(j - 1)) {
// Count both cases
return subCountRec(i - 1, j - 1, txt, pat) +
subCountRec(i - 1, j, txt, pat);
}
return subCountRec(i - 1, j, txt, pat);
}
static int subseqCount(String txt, String pat) {
return subCountRec(txt.length(), pat.length(), txt, pat);
}
public static void main(String[] args) {
String pat = "aba";
String txt = "abba";
System.out.println(subseqCount(txt, pat));
}
}
def subCountRec(i, j, txt, pat):
if j == 0:
# Empty pattern is found in
# all suffixes
return 1
if i == 0:
# No more characters in
# txt to match pat
return 0
if txt[i - 1] == pat[j - 1]:
# Count both cases
return (subCountRec(i - 1, j - 1, txt, pat) +
subCountRec(i - 1, j, txt, pat))
return subCountRec(i - 1, j, txt, pat)
def subseqCount(txt, pat):
return subCountRec(len(txt), len(pat), txt, pat)
if __name__ == "__main__":
pat = "aba"
txt = "abba"
print(subseqCount(txt, pat))
using System;
class GfG
{
static int SubCountRec(int i, int j, string txt, string pat)
{
if (j == 0)
{
// Empty pattern is found in
// all suffixes
return 1;
}
if (i == 0)
{
// No more characters in
// txt to match pat
return 0;
}
if (txt[i - 1] == pat[j - 1])
{
// Count both cases
return SubCountRec(i - 1, j - 1, txt, pat) +
SubCountRec(i - 1, j, txt, pat);
}
return SubCountRec(i - 1, j, txt, pat);
}
static int SubseqCount(string txt, string pat)
{
return SubCountRec(txt.Length, pat.Length, txt, pat);
}
static void Main()
{
string pat = "aba";
string txt = "abba";
Console.WriteLine(SubseqCount(txt, pat));
}
}
function subCountRec(i, j, txt, pat) {
if (j === 0) {
// Empty pattern is found in
// all suffixes
return 1;
}
if (i === 0) {
// No more characters in
// txt to match pat
return 0;
}
if (txt[i - 1] === pat[j - 1]) {
// Count both cases
return subCountRec(i - 1, j - 1, txt, pat) +
subCountRec(i - 1, j, txt, pat);
}
return subCountRec(i - 1, j, txt, pat);
}
function subseqCount(txt, pat) {
return subCountRec(txt.length, pat.length, txt, pat);
}
// Driver Code
let pat = "aba";
let txt = "abba";
console.log(subseqCount(txt, pat));
Output
2
[Better Approach-1] Using Top-Down DP (Recursion) - O(m*n) Time and O(m*n) Space
While employing a recursive approach to this problem, we notice that certain subproblems are computed multiple times, leading to redundancy.
For example, when calculating countSubsequences(i, j), we might find need to calculate countSubsequences(i-1, j-1) and countSubsequences(i, j-1) multiple times for the same indices. This overlapping of computations makes it clear that a simple recursive approach would be inefficient.

- The recursive solution involves changing of two parameters, the current index in the pattern (i) and the current index in the text (j). We need to track both parameters, so we create a 2D array of size (m+1) x (n+1) because the value of i will be in the range [0,m] and j in the range [0,n], where m is the length of the pattern and n is the length of the text.
- We initialize the 2D array with -1 to indicate that no subproblems have been computed yet.
- We check if the value at dp[i][j] is -1. If it is, we proceed to compute else we return the stored result.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int countSubsequences(int i, int j, string &pat, string &txt, vector<vector<int>> &dp)
{
if (i == 0)
return 1;
if (j == 0)
return 0;
// If already computed, return the result
if (dp[i][j] != -1)
return dp[i][j];
// If last characters don't match
if (pat[i - 1] != txt[j - 1])
{
dp[i][j] = countSubsequences(i, j - 1, pat, txt, dp);
}
else
{
// Both characters match
dp[i][j] =
countSubsequences(i, j - 1, pat, txt, dp) + countSubsequences(i - 1, j - 1, pat, txt, dp);
}
return dp[i][j];
}
int subseqCount(string &txt, string &pat)
{
int m = pat.length(), n = txt.length();
// pat can't appear as a subsequence in txt
if (m > n)
return 0;
// Create a 2D vector for memoization
vector<vector<int>> dp(m + 1, vector<int>(n + 1, -1));
return countSubsequences(m, n, pat, txt, dp);
}
int main()
{
string pat = "aba";
string txt = "abba";
cout << subseqCount(txt, pat) << endl;
return 0;
}
import java.util.Arrays;
public class GfG {
static int countSubsequences(int i, int j, String pat, String txt, int[][] dp) {
if (i == 0)
return 1;
if (j == 0)
return 0;
// If already computed
if (dp[i][j] != -1)
return dp[i][j];
// If last characters don't match
if (pat.charAt(i - 1) != txt.charAt(j - 1)) {
dp[i][j] = countSubsequences(i, j - 1, pat, txt, dp);
} else {
// Both characters match
dp[i][j] = countSubsequences(i, j - 1, pat, txt, dp)
+ countSubsequences(i - 1, j - 1, pat, txt, dp);
}
return dp[i][j];
}
static int subseqCount(String txt, String pat) {
int m = pat.length();
int n = txt.length();
// pat can't appear as a subsequence in txt
if (m > n)
return 0;
int[][] dp = new int[m + 1][n + 1];
// initialize dp with -1
for (int x = 0; x <= m; x++)
Arrays.fill(dp[x], -1);
return countSubsequences(m, n, pat, txt, dp);
}
public static void main(String[] args) {
String pat = "aba";
String txt = "abba";
System.out.println(subseqCount(txt, pat));
}
}
def countSubsequences(i, j, pat, txt, dp):
if i == 0:
return 1
if j == 0:
return 0
# If already computed
if dp[i][j] != -1:
return dp[i][j]
# If last characters don't match
if pat[i - 1] != txt[j - 1]:
dp[i][j] = countSubsequences(i, j - 1, pat, txt, dp)
else:
# Characters match
dp[i][j] = (countSubsequences(i, j - 1, pat, txt, dp) +
countSubsequences(i - 1, j - 1, pat, txt, dp))
return dp[i][j]
def subseqCount(txt, pat):
m = len(pat)
n = len(txt)
if m > n:
return 0
dp = [[-1] * (n + 1) for _ in range(m + 1)]
return countSubsequences(m, n, pat, txt, dp)
if __name__ == "__main__":
pat = "aba"
txt = "abba"
print(subseqCount(txt, pat))
using System;
class GfG
{
static int CountSubsequences(int i, int j, string pat, string txt, int[,] dp)
{
if (i == 0)
return 1;
if (j == 0)
return 0;
// If already computed
if (dp[i, j] != -1)
return dp[i, j];
// If last characters don't match
if (pat[i - 1] != txt[j - 1])
{
dp[i, j] = CountSubsequences(i, j - 1, pat, txt, dp);
}
else
{
// Characters match
dp[i, j] = CountSubsequences(i, j - 1, pat, txt, dp) +
CountSubsequences(i - 1, j - 1, pat, txt, dp);
}
return dp[i, j];
}
static int SubseqCount(string txt, string pat)
{
int m = pat.Length;
int n = txt.Length;
if (m > n)
return 0;
int[,] dp = new int[m + 1, n + 1];
for (int a = 0; a <= m; a++)
for (int b = 0; b <= n; b++)
dp[a, b] = -1;
return CountSubsequences(m, n, pat, txt, dp);
}
static void Main()
{
string pat = "aba";
string txt = "abba";
Console.WriteLine(SubseqCount(txt, pat));
}
}
function countSubsequences(i, j, pat, txt, dp) {
if (i === 0)
return 1;
if (j === 0)
return 0;
// If already computed
if (dp[i][j] !== -1)
return dp[i][j];
// If last characters don't match
if (pat[i - 1] !== txt[j - 1]) {
dp[i][j] = countSubsequences(i, j - 1, pat, txt, dp);
} else {
// Characters match
dp[i][j] =
countSubsequences(i, j - 1, pat, txt, dp) +
countSubsequences(i - 1, j - 1, pat, txt, dp);
}
return dp[i][j];
}
function subseqCount(txt, pat) {
let m = pat.length;
let n = txt.length;
if (m > n)
return 0;
let dp = Array.from({ length: m + 1 }, () =>
Array(n + 1).fill(-1)
);
return countSubsequences(m, n, pat, txt, dp);
}
// Driver Code
let pat = "aba";
let txt = "abba";
console.log(subseqCount(txt, pat));
Output
2
[Better Approach-2] Using Bottom-Up DP (Tabulation) - O(m*n) Time and O(m*n) Space
Our approach is similar to the previous one, just instead recursion, we iteratively build up the solution by calculating in bottom-up manner. Maintain 2D table dp of size (m + 1) x (n + 1), where m is the length of the pattern and n is the length of the text.
Our table will store the number of distinct subsequences of the pattern in the text at various indices.
- For all j from 0 to n, set dp[0][j] = 1. This represents the fact that an empty pattern is a subsequence of any text (including an empty text).
- For i > 0, set dp[i][0] = 0. This indicates that a non-empty pattern cannot be found in an empty text.
Iterate through the table filling it out from 1 to m for the pattern and 1 to n for the text. For each i (from 1 to m) and j (from 1 to n):
if pat[i - 1] == txt[j - 1], then we have two choices:
- Include this character in the subsequence, which gives dp[i - 1][j - 1].
- Exclude this character, which gives dp[i][j - 1]
If the characters do not match, we can only exclude the current character of txt, dp[i][j]=dp[i][j-1].
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int subseqCount(string &txt, string &pat)
{
int m = pat.length(), n = txt.length();
// pat can't appear as a subsequence in txt
if (m > n)
return 0;
// Create a 2D vector initialized with 0
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
// Initializing first row with all 1s. An empty
// string is a subsequence of all.
for (int j = 0; j <= n; j++)
dp[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 txt.
if (pat[i - 1] != txt[j - 1])
dp[i][j] = dp[i][j - 1];
else
// Value is obtained considering two cases.
// a) All substrings without last character in txt
// b) All substrings without last characters in both.
dp[i][j] = (dp[i][j - 1] + dp[i - 1][j - 1]);
}
}
return dp[m][n];
}
int main()
{
string pat = "aba";
string txt = "abba";
cout << subseqCount(txt, pat) << endl;
return 0;
}
public class GfG {
static int subseqCount(String txt, String pat) {
int m = pat.length();
int n = txt.length();
// pat can't appear as a subsequence in txt
if (m > n)
return 0;
// 2D array initialized with 0
int[][] dp = new int[m + 1][n + 1];
// Initializing first row with all 1s. An empty
// string is a subsequence of all.
for (int j = 0; j <= n; j++)
dp[0][j] = 1;
// Fill dp[][] in bottom up manner
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
// If last characters don't match
if (pat.charAt(i - 1) != txt.charAt(j - 1)) {
dp[i][j] = dp[i][j - 1];
} else {
// Value from:
// a) without last character in txt
// b) without last characters in both
dp[i][j] = dp[i][j - 1] + dp[i - 1][j - 1];
}
}
}
return dp[m][n];
}
public static void main(String[] args) {
String pat = "aba";
String txt = "abba";
System.out.println(subseqCount(txt, pat));
}
}
def subseqCount(txt, pat):
m = len(pat)
n = len(txt)
# pat can't appear as a subsequence in txt
if m > n:
return 0
# Create a 2D dp list initialized with 0
dp = [[0] * (n + 1) for _ in range(m + 1)]
# Empty pattern is subsequence of all prefixes
for j in range(n + 1):
dp[0][j] = 1
# Fill dp[][] bottom-up
for i in range(1, m + 1):
for j in range(1, n + 1):
# If last characters don't match
if pat[i - 1] != txt[j - 1]:
dp[i][j] = dp[i][j - 1]
else:
# Value from:
# a) without last character in txt
# b) without last characters in both
dp[i][j] = dp[i][j - 1] + dp[i - 1][j - 1]
return dp[m][n]
if __name__ == "__main__":
pat = "aba"
txt = "abba"
print(subseqCount(txt, pat))
using System;
class GfG
{
static int SubseqCount(string txt, string pat)
{
int m = pat.Length;
int n = txt.Length;
// pat can't appear as a subsequence in txt
if (m > n)
return 0;
// Create 2D dp array initialized with 0
int[,] dp = new int[m + 1, n + 1];
// Empty pattern is a subsequence of all prefixes
for (int j = 0; j <= n; j++)
dp[0, j] = 1;
// Fill dp[][] bottom-up
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= n; j++)
{
// If last characters don't match
if (pat[i - 1] != txt[j - 1])
{
dp[i, j] = dp[i, j - 1];
}
else
{
// a) without last character in txt
// b) without last characters in both
dp[i, j] = dp[i, j - 1] + dp[i - 1, j - 1];
}
}
}
return dp[m, n];
}
static void Main()
{
string pat = "aba";
string txt = "abba";
Console.WriteLine(SubseqCount(txt, pat));
}
}
function subseqCount(txt, pat) {
let m = pat.length;
let n = txt.length;
// pat can't appear as a subsequence in txt
if (m > n)
return 0;
// 2D dp array initialized with 0
let dp = Array.from({ length: m + 1 }, () =>
Array(n + 1).fill(0)
);
// Empty pattern is a subsequence of all prefixes
for (let j = 0; j <= n; j++)
dp[0][j] = 1;
// Fill dp[][] bottom-up
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
// If last characters don't match
if (pat[i - 1] !== txt[j - 1]) {
dp[i][j] = dp[i][j - 1];
} else {
// a) without last character in txt
// b) without last characters in both
dp[i][j] = dp[i][j - 1] + dp[i - 1][j - 1];
}
}
}
return dp[m][n];
}
// Driver Code
let pat = "aba";
let txt = "abba";
console.log(subseqCount(txt, pat));
Output
2
[Expected Approach ] Using Space Optimized DP – O(m*n) Time and O(m) Space
Since dp[i][j] accesses elements of the current and previous rows only, we can optimize auxiliary space just by using two rows only reducing space from m*n to 2*m.
So we maintain two arrays prev and curr to store previous and current rows of dp[][].
if pat[i - 1] == txt[j - 1], then we have two choices:
- Include this character in the subsequence, which gives prev[j-1] is added to curr[j]
- Exclude this character, which means prev[j] is added to curr[j]
If the characters do not match, we can only exclude the current character which means curr[j] = prev[j]
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int subseqCount(string &txt, string &pat)
{
int m = pat.length(), n = txt.length();
// If pattern is longer than the text, return 0
if (m > n)
return 0;
// Create two 1D arrays for dynamic programming
vector<int> prev(m + 1, 0);
vector<int> curr(m + 1, 0);
// Base case: An empty pattern can be
// formed from any text
prev[0] = 1;
// Iterate over each character in the text
for (int i = 1; i <= n; i++)
{
// Base case: An empty pattern is always
// a subsequence
curr[0] = 1;
// Iterate over each character in the pattern
for (int j = 1; j <= m; j++)
{
// If characters match, include or
// exclude the current character
if (txt[i - 1] == pat[j - 1])
{
curr[j] = (prev[j - 1] + prev[j]);
}
else
{
curr[j] = prev[j];
}
}
// Update prev array for
// the next iteration
prev = curr;
}
return prev[m];
}
int main()
{
string pat = "aba";
string txt = "abba";
cout << subseqCount(txt, pat) << endl;
return 0;
}
public class GfG {
public static int subseqCount(String txt, String pat) {
int m = pat.length(), n = txt.length();
// If pattern is longer than the
// text, return 0
if (m > n)
return 0;
// Create two arrays for dynamic
// programming
int[] prev = new int[m + 1];
int[] curr = new int[m + 1];
// Base case: An empty pattern can
// be formed from any text
prev[0] = 1;
// Iterate over each character in the text
for (int i = 1; i <= n; i++) {
curr[0] = 1;
// Iterate over each character in the pattern
for (int j = 1; j <= m; j++) {
// If characters match, include or exclude
// the current character
if (txt.charAt(i - 1) == pat.charAt(j - 1)) {
curr[j] = (prev[j - 1] + prev[j]);
} else {
curr[j] = prev[j];
}
}
// Update prev array for the next
// iteration
for (int j = 0; j <= m; j++)
prev[j] = curr[j];
}
// Return the count of distinct subsequences
// matching the complete pattern
return prev[m];
}
public static void main(String[] args) {
String pat = "aba";
String txt = "abba";
System.out.println(subseqCount(txt, pat));
}
}
def subseqCount(txt, pat):
m = len(pat)
n = len(txt)
# If pattern is longer than the
# text, return 0
if m > n:
return 0
# Create two arrays for dynamic
# programming
prev = [0] * (m + 1)
curr = [0] * (m + 1)
# Base case: An empty pattern can
# be formed from any text
prev[0] = 1
# Iterate over each character in the text
for i in range(1, n + 1):
curr[0] = 1
# Iterate over each character in the pattern
for j in range(1, m + 1):
# If characters match, include or exclude
# the current character
if txt[i - 1] == pat[j - 1]:
curr[j] = prev[j - 1] + prev[j]
else:
curr[j] = prev[j]
# Update prev array for the next
# iteration
prev = curr[:]
# Return the count of distinct subsequences
# matching the complete pattern
return prev[m]
if __name__ == "__main__":
pat = "aba"
txt = "abba"
print(subseqCount(txt, pat))
using System;
class GfG
{
static int SubseqCount(string txt, string pat)
{
int m = pat.Length;
int n = txt.Length;
// pat can't appear as a subsequence in txt
if (m > n)
return 0;
// Create two 1D arrays for space-optimized DP
int[] prev = new int[m + 1];
int[] curr = new int[m + 1];
// Empty pattern is a subsequence of any text
prev[0] = 1;
// Iterate over text
for (int i = 1; i <= n; i++)
{
// Empty pattern always has 1 way
curr[0] = 1;
// Iterate over pattern
for (int j = 1; j <= m; j++)
{
// Reset current cell
curr[j] = 0;
// If characters match → include + exclude
if (txt[i - 1] == pat[j - 1])
{
curr[j] += prev[j - 1]; // include
}
curr[j] += prev[j]; // exclude
}
// Move curr into prev for next iteration
Array.Copy(curr, prev, m + 1);
}
return prev[m];
}
static void Main()
{
string pat = "aba";
string txt = "abba";
Console.WriteLine(SubseqCount(txt, pat));
}
}
function subseqCount(txt, pat) {
const m = pat.length, n = txt.length;
// If pattern is longer than the
// text, return 0
if (m > n) return 0;
// Create two arrays for dynamic
// programming
let prev = new Array(m + 1).fill(0);
let curr = new Array(m + 1).fill(0);
// Base case: An empty pattern can
// be formed from any text
prev[0] = 1;
// Iterate over each character in the text
for (let i = 1; i <= n; i++) {
curr[0] = 1;
// Iterate over each character in the pattern
for (let j = 1; j <= m; j++) {
// If characters match, include or exclude
// the current character
if (txt[i - 1] === pat[j - 1]) {
curr[j] = prev[j - 1] + prev[j];
} else {
curr[j] = prev[j];
}
}
// Update prev array for the next
// iteration
prev = curr.slice();
}
// Return the count of distinct subsequences
// matching the complete pattern
return prev[m];
}
// Driver Code
let pat = "aba";
let txt = "abba";
console.log(subseqCount(txt, pat));
Output
2