Given a string str, Find the number of distinct subsequences that can be formed from it.
A subsequence is a sequence derived from the original string by deleting zero or more characters without changing the relative order of the remaining characters.
Note: Answer can be very large, so, ouput will be answer modulo 109+7.
Examples:
Input: str = "gfg"
Output: 7
Explanation: The seven distinct subsequences are "", "g", "f", "gf", "fg", "gg" and "gfg"Input: str = "ggg"
Output: 4
Explanation: The four distinct subsequences are "", "g", "gg" and "ggg"
Table of Content
[Naive Approach] By Generating All Subsequences - O(2 ^ n) Time and O(2 ^ n) Space
The idea is to generate every possible subsequence of the string and store them in a HashSet to ensure uniqueness. To do this, we apply recursion on each index of the string. For every character at index i, we have two choices:
- Include str[i]: Add the current character to the subsequence being built and move to the next index.
- Exclude str[i]: Skip the current character and move to the next index.
The recursion stops when we reach the end of the string, meaning no more characters are left to process. At that point, we insert the generated subsequence into the HashSet.
//Driver Code Starts
#include <iostream>
#include <unordered_set>
#include <string>
using namespace std;
//Driver Code Ends
const int mod = 1e9+7;
void generateSubseq(int ind, string &cur, string &str, unordered_set<string> &s) {
int n = str.size();
// if the end of string is reached
// store the subsequence in set
if(ind == n) {
s.insert(cur);
return;
}
// skip the current character
generateSubseq(ind + 1, cur, str, s);
// add the character str[i]
cur.push_back(str[ind]);
generateSubseq(ind + 1, cur, str, s);
// remove the added character
cur.pop_back();
}
int distinctSubseq(string &str) {
// to store the unique subsequences
unordered_set<string> s;
// to store current subsequence
string cur;
generateSubseq(0, cur, str, s);
int ans = (int)s.size();
return ans % mod;
}
//Driver Code Starts
int main() {
string str = "gfg";
cout << distinctSubseq(str);
return 0;
}
//Driver Code Ends
//Driver Code Starts
import java.util.HashSet;
class GFG {
//Driver Code Ends
static final int mod = 1000000007;
static void generateSubseq(int ind, StringBuilder cur,
String str, HashSet<String> s) {
int n = str.length();
// if the end of string is reached
// store the subsequence in set
if(ind == n) {
s.add(cur.toString());
return;
}
// skip the current character
generateSubseq(ind + 1, cur, str, s);
// add the character str[i]
cur.append(str.charAt(ind));
generateSubseq(ind + 1, cur, str, s);
// remove the added character
cur.deleteCharAt(cur.length() - 1);
}
static int distinctSubseq(String str) {
// to store the unique subsequences
HashSet<String> s = new HashSet<>();
// to store current subsequence
StringBuilder cur = new StringBuilder();
generateSubseq(0, cur, str, s);
int ans = s.size();
return ans % mod;
}
//Driver Code Starts
public static void main(String[] args) {
String str = "gfg";
System.out.println(distinctSubseq(str));
}
}
//Driver Code Ends
mod = 1000000007
def generateSubseq(ind, cur, s, st):
n = len(s)
# if the end of string is reached
# store the subsequence in set
if ind == n:
st.add(cur)
return
# skip the current character
generateSubseq(ind + 1, cur, s, st)
# add the character s[i]
generateSubseq(ind + 1, cur + s[ind], s, st)
def distinctSubseq(s):
# to store the unique subsequences
st = set()
# to store current subsequence
cur = ""
generateSubseq(0, cur, s, st)
ans = len(st)
return ans % mod
#Driver Code Starts
if __name__ == "__main__":
s = "gfg"
print(distinctSubseq(s))
#Driver Code Ends
//Driver Code Starts
using System;
using System.Text;
using System.Collections.Generic;
class GFG {
//Driver Code Ends
static int mod = 1000000007;
static void generateSubseq(int ind, StringBuilder cur,
string str, HashSet<string> s) {
int n = str.Length;
// if the end of string is reached
// store the subsequence in set
if (ind == n)
{
s.Add(cur.ToString());
return;
}
// skip the current character
generateSubseq(ind + 1, cur, str, s);
// add the character str[i]
cur.Append(str[ind]);
generateSubseq(ind + 1, cur, str, s);
// remove the added character
cur.Remove(cur.Length - 1, 1);
}
static int distinctSubseq(string str)
{
// to store the unique subsequences
HashSet<string> s = new HashSet<string>();
// to store current subsequence
StringBuilder cur = new StringBuilder();
generateSubseq(0, cur, str, s);
int ans = s.Count;
return ans % mod;
}
//Driver Code Starts
public static void Main()
{
string str = "gfg";
Console.WriteLine(distinctSubseq(str));
}
}
//Driver Code Ends
const mod = 1000000007;
function generateSubseq(ind, cur, str, set) {
let n = str.length;
// if the end of string is reached
// store the subsequence in set
if (ind === n) {
set.add(cur);
return;
}
// skip the current character
generateSubseq(ind + 1, cur, str, set);
// add the character str[i]
generateSubseq(ind + 1, cur + str[ind], str, set);
}
function distinctSubseq(str) {
// to store the unique subsequences
let set = new Set();
// to store current subsequence
let cur = "";
generateSubseq(0, cur, str, set);
let ans = set.size;
return ans % mod;
}
//Driver Code Starts
// Driver code
let str = "gfg";
console.log(distinctSubseq(str));
//Driver Code Ends
Output
7
[Expected Approach] Using Dynamic Programming - O(n) Time and O(n) Space
The idea is to use dynamic programming (DP) to efficiently count all distinct subsequences while avoiding duplicates caused by repeating characters.
We use a DP array dp[i] where each element stores the number of distinct subsequences for the first i characters, with dp[0] = 1 for the empty subsequence. For each character, subsequences can either include or exclude it, so the total doubles. To avoid counting duplicates when a character repeats, we track its last occurrence in a last[] array and subtract the subsequences counted up to its previous occurrence. This ensures all subsequences are counted exactly once.
By iteratively updating the DP array and the last occurrence array for every character, we ensure that each subsequence is counted exactly once. At the end, dp[n] contains the total number of distinct subsequences.
//Driver Code Starts
#include <iostream>
#include <vector>
#include <string>
using namespace std;
//Driver Code Ends
int distinctSubseq(string &str) {
int n = str.size();
int mod = 1000000007;
// to store the results up to
// each index i, from 0 to n
vector<int> dp(n + 1, 0);
dp[0] = 1;
// to store the last occurrence
// of each character in the string
vector<int> last(26, -1);
for(int i = 1; i <= n; i++) {
dp[i] = (2 * dp[i - 1]) % mod;
// if the character is seen before
// subtract the count of subsequences
if(last[str[i - 1] - 'a'] != -1) {
dp[i] = (dp[i] - dp[last[str[i - 1] - 'a']] + mod) % mod;
}
// update the last occurrence of the character
last[str[i - 1] - 'a'] = i - 1;
}
return dp[n];
}
//Driver Code Starts
int main() {
string str = "gfg";
cout << distinctSubseq(str);
return 0;
}
//Driver Code Ends
//Driver Code Starts
import java.util.Arrays;
class GFG {
//Driver Code Ends
static int distinctSubseq(String str) {
int n = str.length();
int mod = 1000000007;
// to store the results up to
// each index i, from 0 to n
int[] dp = new int[n + 1];
dp[0] = 1;
// to store the last occurrence
// of each character in the string
int[] last = new int[26];
Arrays.fill(last, -1);
for (int i = 1; i <= n; i++) {
dp[i] = (2 * dp[i - 1]) % mod;
// if the character is seen before
// subtract the count of subsequences
int idx = str.charAt(i - 1) - 'a';
if (last[idx] != -1) {
dp[i] = (dp[i] - dp[last[idx]] + mod) % mod;
}
// update the last occurrence of the character
last[idx] = i - 1;
}
return dp[n];
}
//Driver Code Starts
public static void main(String[] args) {
String str = "gfg";
System.out.println(distinctSubseq(str));
}
}
//Driver Code Ends
mod = 1000000007
def distinctSubseq(str):
n = len(str)
# to store the results up to
# each index i, from 0 to n
dp = [0] * (n + 1)
dp[0] = 1
# to store the last occurrence
# of each character in the string
last = [-1] * 26
for i in range(1, n + 1):
dp[i] = (2 * dp[i - 1]) % mod
# if the character is seen before
# subtract the count of subsequences
idx = ord(str[i - 1]) - ord('a')
if last[idx] != -1:
dp[i] = (dp[i] - dp[last[idx]] + mod) % mod
# update the last occurrence of the character
last[idx] = i - 1
return dp[n]
#Driver Code Starts
if __name__ == "__main__":
str = "gfg"
print(distinctSubseq(str))
#Driver Code Ends
//Driver Code Starts
using System;
class GFG {
//Driver Code Ends
static int distinctSubseq(string str) {
int n = str.Length;
int mod = 1000000007;
// to store the results up to
// each index i, from 0 to n
int[] dp = new int[n + 1];
dp[0] = 1;
// to store the last occurrence
// of each character in the string
int[] last = new int[26];
for (int i = 0; i < 26; i++) last[i] = -1;
for (int i = 1; i <= n; i++) {
dp[i] = (int)((2L * dp[i - 1]) % mod);
// if the character is seen before
// subtract the count of subsequences
int idx = str[i - 1] - 'a';
if (last[idx] != -1) {
dp[i] = (dp[i] - dp[last[idx]] + mod) % mod;
}
// update the last occurrence of the character
last[idx] = i - 1;
}
return dp[n];
}
//Driver Code Starts
static void Main() {
string str = "gfg";
Console.WriteLine(distinctSubseq(str));
}
}
//Driver Code Ends
function distinctSubseq(str) {
let n = str.length;
const mod = 1000000007;
// to store the results up to
// each index i, from 0 to n
let dp = Array(n + 1).fill(0);
dp[0] = 1;
// to store the last occurrence
// of each character in the string
let last = Array(26).fill(-1);
for (let i = 1; i <= n; i++) {
dp[i] = (2 * dp[i - 1]) % mod;
// if the character is seen before
// subtract the count of subsequences
let idx = str.charCodeAt(i - 1) - 'a'.charCodeAt(0);
if (last[idx] != -1) {
dp[i] = (dp[i] - dp[last[idx]] + mod) % mod;
}
// update the last occurrence of the character
last[idx] = i - 1;
}
return dp[n];
}
//Driver Code Starts
// Driver Code
let str = "gfg";
console.log(distinctSubseq(str));
//Driver Code Ends
Output
7
[Space Optimized] - O(n) Time and O(1) Space
In the above approach, we use an array to store the last occurrence of each character, which is further used to access value stored in array dp[], but instead of doing so we can directly store the result at last of occurrence of each character, thus we will not required an additional array to store the results.
//Driver Code Starts
#include <iostream>
#include <vector>
#include <string>
using namespace std;
//Driver Code Ends
int distinctSubseq(string &str) {
int n = str.size();
int mod = 1000000007;
// to store the last occurrence
// of each character in the string
vector<int> last(26, 0);
// to store result after each index
int res = 1;
for(int i = 1; i <= n; i++) {
// double the count of unique subsequences
// and remove the repetition
int cur = ( (2LL * res) % mod - last[str[i - 1] - 'a'] + mod ) % mod;
// update the last occurrence of the character
last[str[i - 1] - 'a'] = res;
res = cur;
}
return res;
}
//Driver Code Starts
int main() {
string str = "gfg";
cout << distinctSubseq(str);
return 0;
}
//Driver Code Ends
//Driver Code Starts
class GfG {
//Driver Code Ends
static int distinctSubseq(String str) {
int n = str.length();
int mod = 1000000007;
// to store the last occurrence
// of each character in the string
int[] last = new int[26];
// to store result after each index
int res = 1;
for (int i = 1; i <= n; i++) {
// double the count of unique subsequences
// and remove the repetition
int cur = (int)(((2L * res) % mod -
last[str.charAt(i - 1) - 'a'] + mod) % mod);
// update the last occurrence of the character
last[str.charAt(i - 1) - 'a'] = res;
res = cur;
}
return res;
}
//Driver Code Starts
public static void main(String[] args) {
String str = "gfg";
System.out.println(distinctSubseq(str));
}
}
//Driver Code Ends
def distinctSubseq(s):
n = len(s)
MOD = 10**9 + 7
# to store the last occurrence
# of each character in the string
last = [0] * 26
# to store result after each index
res = 1
for i in range(1, n + 1):
# double the count of unique subsequences
# and remove the repetition
idx = ord(s[i - 1]) - ord('a')
cur = (2 * res - last[idx]) % MOD
# update the last occurrence of the character
last[idx] = res
res = cur
return res
#Driver Code Starts
if __name__ == "__main__":
s = "gfg"
print(distinctSubseq(s))
#Driver Code Ends
//Driver Code Starts
using System;
class GFG
{
//Driver Code Ends
static int distinctSubseq(string str)
{
int n = str.Length;
const int MOD = 1000000007;
// to store the last occurrence
// of each character in the string
int[] last = new int[26];
// to store result after each index
int res = 1;
for (int i = 1; i <= n; i++)
{
// double the count of unique subsequences
// and remove the repetition
int idx = str[i - 1] - 'a';
int cur = ((2 * res - last[idx]) % MOD + MOD) % MOD;
// update the last occurrence of the character
last[idx] = res;
res = cur;
}
return res;
}
//Driver Code Starts
static void Main()
{
string str = "gfg";
Console.WriteLine(distinctSubseq(str));
}
}
//Driver Code Ends
function distinctSubseq(str) {
const n = str.length;
const MOD = 1e9 + 7;
// to store the last occurrence
// of each character in the string
const last = new Array(26).fill(0);
// to store result after each index
let res = 1;
for (let i = 1; i <= n; i++) {
// double the count of unique subsequences
// and remove the repetition
const idx = str.charCodeAt(i - 1) - 97;
let cur = ((2 * res - last[idx]) % MOD + MOD) % MOD;
// update the last occurrence of the character
last[idx] = res;
res = cur;
}
return res;
}
//Driver Code Starts
// Driver Code
const str = "gfg";
console.log(distinctSubseq(str));
//Driver Code Ends
Output
7