Given a pair of stringsĀ s1Ā andĀ s2Ā of equal lengths, your task is to find which of the two strings has moreĀ distinct subsequences. If both strings have the same number of distinct subsequences, returnĀ s1.
Examples:
Input: s1 = "gfg", s2 = "ggg"
Output: "gfg"
Explanation: "gfg" have 6 distinct subsequences whereas "ggg" have 3 distinct subsequences.Input: s1 = "a", s2 = "b"
Output: "a"
Explanation: Both the strings have only 1 distinct subsequence.
Table of Content
[Naive Approach] Generates all unique subsequences - O(2^m + 2^n) Time and O(2^m + 2^n) Space
Idea is to generates all unique subsequences of two input strings using recursion and stores them in an unordered set to automatically eliminate duplicates. By comparing the number of unique subsequences in each string, we determine which string is better that is, the one with more unique subsequences. The use of a global set simplifies tracking uniqueness without requiring additional logic.
We use a set to track and count all distinct subsequences of the given string. Below is an illustration demonstrating how the subsequences are generated for the string "gfg".

In the end, the set contains only the distinct subsequences of the string 'gfg', such as '', 'g', 'f', 'gf', 'fg', 'gg', and 'gfg'. These represent all the unique combinations that can be formed by either including or excluding each character from the original string.
#include <bits/stdc++.h>
using namespace std;
// Global unordered set to store unique subsequences
unordered_set<string> sn;
// Function to generate all unique subsequences
void subsequences(string& s, string op, int i) {
if (i == s.size()) {
sn.insert(op);
return;
}
// Include current character
subsequences(s, op + s[i], i + 1);
// Exclude current character
subsequences(s, op, i + 1);
}
// Function to return the string with more unique subsequences
string betterString(string str1, string str2) {
subsequences(str1, "", 0);
int a = sn.size();
sn.clear();
subsequences(str2, "", 0);
int b = sn.size();
return (b > a) ? str2 : str1;
}
int main() {
string str1 = "gfg";
string str2 = "ggg";
cout << betterString(str1, str2);
return 0;
}
import java.util.HashSet;
import java.util.Set;
class GfG{
static Set<String> sn = new HashSet<>();
// Function to generate all unique subsequences
public static void subsequences(String s, String op, int i){
if (i == s.length()) {
sn.add(op);
return;
}
// Include current character
subsequences(s, op + s.charAt(i), i + 1);
// Exclude current character
subsequences(s, op, i + 1);
}
// Function to return the string with more unique
// subsequences
static String betterString(String str1, String str2){
subsequences(str1, "", 0);
int a = sn.size();
sn.clear();
subsequences(str2, "", 0);
int b = sn.size();
return (b > a) ? str2 : str1;
}
public static void main(String[] args) {
String str1 = "gfg";
String str2 = "ggg";
System.out.println(betterString(str1, str2));
}
}
# Global set to store unique subsequences
sn = set()
def subsequences(s, op, i):
if i == len(s):
# Exclude empty strings
if op:
sn.add(op)
return
# Include current character
subsequences(s, op + s[i], i + 1)
# Exclude current character
subsequences(s, op, i + 1)
def betterString(str1, str2):
global sn
sn.clear()
subsequences(str1, "", 0)
a = len(sn)
sn.clear()
subsequences(str2, "", 0)
b = len(sn)
return str2 if b > a else str1
if __name__ == "__main__":
str1 = "gfg"
str2 = "ggg"
print(betterString(str1, str2))
using System;
using System.Collections.Generic;
class GfG {
// Global unordered set to store unique subsequences
private static HashSet<string> sn = new HashSet<string>();
// Function to generate all unique subsequences
private static void subsequences(string s, string op, int i){
if (i == s.Length){
sn.Add(op);
return;
}
// Include current character
subsequences(s, op + s[i], i + 1);
// Exclude current character
subsequences(s, op, i + 1);
}
// Function to return the string with more unique subsequences
public static string betterString(string str1, string str2){
subsequences(str1, "", 0);
int a = sn.Count;
sn.Clear();
subsequences(str2, "", 0);
int b = sn.Count;
return (b > a) ? str2 : str1;
}
static void Main()
{
string str1 = "gfg";
string str2 = "ggg";
Console.WriteLine(betterString(str1, str2));
}
}
// Global set to store unique subsequences
const sn = new Set();
// Function to generate all unique subsequences
function subsequences(s, op, i) {
if (i === s.length) {
// Exclude empty strings
if (op !== "") {
sn.add(op);
}
return;
}
// Include current character
subsequences(s, op + s[i], i + 1);
// Exclude current character
subsequences(s, op, i + 1);
}
// Function to return the string with more unique subsequences
function betterString(str1, str2) {
sn.clear();
subsequences(str1, "", 0);
const a = sn.size;
sn.clear();
subsequences(str2, "", 0);
const b = sn.size;
return b > a ? str2 : str1;
}
// Driver Code
const str1 = "gfg";
const str2 = "ggg";
console.log(betterString(str1, str2));
Output
gfg
[Better Approach] Using Dynamic Programming - O(n) Time and O(n) Space
Idea is to use dynamic programming to efficiently count the number of distinct subsequences in each string, avoiding the exponential complexity of generating them explicitly. By tracking the last occurrence of each character, it ensures that duplicate subsequences caused by repeated characters are subtracted correctly.
Illustration:
#include <bits/stdc++.h>
using namespace std;
// Function to count distinct subsequences using Dynamic Programming
int countSub(string s) {
// To track last occurrence of each character
vector<int> last(26, -1);
int n = s.length();
// dp[i] stores count of distinct subsequences of length i
vector<int> dp(n + 1);
// Empty string has one subsequence: ""
dp[0] = 1;
for (int i = 1; i <= n; i++) {
dp[i] = 2 * dp[i - 1];
if (last[s[i - 1] - 'a'] != -1)
dp[i] -= dp[last[s[i - 1] - 'a']];
last[s[i - 1] - 'a'] = i - 1;
}
return dp[n];
}
// Function to return the better string with more distinct subsequences
string betterString(string s1, string s2) {
int a = countSub(s1);
int b = countSub(s2);
return (a < b) ? s2 : s1;
}
int main() {
string s1 = "gfg";
string s2 = "ggg";
cout << betterString(s1, s2);
return 0;
}
import java.util.*;
public class GfG {
// Function to count distinct subsequences using Dynamic Programming
public static int countSub(String s) {
int n = s.length();
int[] last = new int[26];
Arrays.fill(last, -1);
int[] dp = new int[n + 1];
// Empty string has one subsequence
dp[0] = 1;
for (int i = 1; i <= n; i++) {
dp[i] = 2 * dp[i - 1];
if (last[s.charAt(i - 1) - 'a'] != -1) {
dp[i] -= dp[last[s.charAt(i - 1) - 'a']];
}
last[s.charAt(i - 1) - 'a'] = i - 1;
}
return dp[n];
}
// Function to return the better string with more distinct subsequences
public static String betterString(String s1, String s2) {
int a = countSub(s1);
int b = countSub(s2);
return (a < b) ? s2 : s1;
}
public static void main(String[] args) {
String s1 = "gfg";
String s2 = "ggg";
System.out.println(betterString(s1, s2));
}
}
def countSub(s):
n = len(s)
last = [-1] * 26
dp = [0] * (n + 1)
# Empty string has one subsequence
dp[0] = 1
for i in range(1, n + 1):
dp[i] = 2 * dp[i - 1]
char_index = ord(s[i - 1])
if last[char_index - ord('a')] != -1:
dp[i] -= dp[last[char_index - ord('a')]]
last[char_index - ord('a')] = i - 1
return dp[n]
def betterString(s1, s2):
a = countSub(s1)
b = countSub(s2)
return s2 if a < b else s1
# Driver Code
if __name__ == "__main__":
s1 = "gfg"
s2 = "ggg"
print(betterString(s1, s2))
using System;
using System.Collections.Generic;
class GfG
{
// Function to count distinct subsequences using Dynamic Programming
static int countSub(string s)
{
int n = s.Length;
int[] last = new int[26];
Array.Fill(last, -1);
int[] dp = new int[n + 1];
dp[0] = 1; // Empty string has one subsequence
for (int i = 1; i <= n; i++)
{
dp[i] = 2 * dp[i - 1];
if (last[s[i - 1] - 'a'] != -1)
dp[i] -= dp[last[s[i - 1] - 'a']];
last[s[i - 1] - 'a'] = i - 1;
}
return dp[n];
}
// Function to return the better string with more distinct subsequences
static string betterString(string s1, string s2)
{
int a = countSub(s1);
int b = countSub(s2);
return (a < b) ? s2 : s1;
}
static void Main()
{
string s1 = "gfg";
string s2 = "ggg";
Console.WriteLine(betterString(s1, s2));
}
}
function countSub(s) {
let n = s.length;
let last = new Array(26).fill(-1);
let dp = new Array(n + 1).fill(0);
// Empty string has one subsequence
dp[0] = 1;
for (let i = 1; i <= n; i++) {
dp[i] = 2 * dp[i - 1];
let char_index = s.charCodeAt(i - 1);
if (last[char_index - 'a'.charCodeAt(0)]!= -1) {
dp[i] -= dp[last[char_index - 'a'.charCodeAt(0)]];
}
last[char_index - 'a'.charCodeAt(0)] = i - 1;
}
return dp[n];
}
function betterString(s1, s2) {
let a = countSub(s1);
let b = countSub(s2);
return a < b? s2 : s1;
}
// Driver Code
let s1 = "gfg";
let s2 = "ggg";
console.log(betterString(s1, s2));
Output
gfg
[Expected Approach] Space Optimization - 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. Please count the number of distinct subsequences for more details.
#include <bits/stdc++.h>
using namespace std;
// to find the count of unique subsequences
int countSub(string &s) {
int n = s.size();
// 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 = 2 * res - last[s[i - 1] - 'a'];
// update the last occurrence of the character
last[s[i - 1] - 'a'] = res;
res = cur;
}
return res;
}
// Function to return the better string with more distinct subsequences
string betterString(string s1, string s2) {
int a = countSub(s1);
int b = countSub(s2);
return (a < b) ? s2 : s1;
}
int main() {
string s1 = "gfg";
string s2 = "ggg";
cout << betterString(s1, s2);
return 0;
}
import java.util.*;
public class GfG {
// Function to count distinct subsequences using Dynamic Programming
static int countSub(String s) {
int n = s.length();
// to store the results up to
// each index i, from 0 to n
int[] last = new int[26];
Arrays.fill(last, 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 = 2 * res - last[s.charAt(i - 1) - 'a'];
// update the last occurrence of the character
last[s.charAt(i - 1) - 'a'] = res;
res = cur;
}
return res;
}
// Function to return the better string with more distinct subsequences
public static String betterString(String s1, String s2) {
int a = countSub(s1);
int b = countSub(s2);
return (a < b) ? s2 : s1;
}
public static void main(String[] args) {
String s1 = "gfg";
String s2 = "ggg";
System.out.println(betterString(s1, s2));
}
}
def countSub(s):
n = len(s)
# 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
cur = 2 * res - last[ord(s[i - 1]) - ord('a')]
# update the last occurrence of the character
last[ord(s[i - 1]) - ord('a')] = res
res = cur
return res
def betterString(s1, s2):
a = countSub(s1)
b = countSub(s2)
return s2 if a < b else s1
# Driver Code
if __name__ == "__main__":
s1 = "gfg"
s2 = "ggg"
print(betterString(s1, s2))
using System;
using System.Collections.Generic;
class GfG{
// Function to count distinct subsequences using Dynamic Programming
public static int countSub(string s) {
int n = s.Length;
// 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] = 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 = 2 * res - last[s[i - 1] - 'a'];
// update the last occurrence of the character
last[s[i - 1] - 'a'] = res;
res = cur;
}
return res;
}
// Function to return the better string with more distinct subsequences
static string betterString(string s1, string s2){
int a = countSub(s1);
int b = countSub(s2);
return (a < b) ? s2 : s1;
}
static void Main(){
string s1 = "gfg";
string s2 = "ggg";
Console.WriteLine(betterString(s1, s2));
}
}
// to find the count of unique subsequences
function countSub(s) {
let n = s.length;
// to store the last occurrence
// of each character in the string
let 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
let cur = 2 * res -
last[s.charCodeAt(i - 1) - 'a'.charCodeAt(0)];
// update the last occurrence of the character
last[s.charCodeAt(i - 1) - 'a'.charCodeAt(0)] = res;
res = cur;
}
return res;
}
function betterString(s1, s2) {
const a = countSub(s1);
const b = countSub(s2);
return (a < b) ? s2 : s1;
}
// Example usage
const s1 = "gfg";
const s2 = "ggg";
console.log(betterString(s1, s2));
Output
gfg