Given a string s, find all unique subsequences of s which start with a vowel and end with a consonant.
- The result must be returned in lexicographically sorted order.
- If there are no valid subsequences, return an empty list.
Examples:
Input: s = "abc"
Output: ["ab", "abc", "ac"]
Explanation: "ab", "abc" and "ac" are all possible unique subsequences which start with a vowel and end with a consonant.Input: s = "rtmkstdh"
Output: [ ]
Explanation: There are no valid subsequences since the string contains no vowels.
Table of Content
[Naive Approach] Using Recursion and Backtracking - O(n * 2^n) Time and O(n * 2^n) Space
The idea is to generate all possible subsequences of the string using recursion. At each index we make two choices - include the current character or exclude it. Once we reach the end of the string, we check if the generated subsequence starts with a vowel and ends with a consonant. We use an ordered set to automatically handle duplicates and maintain lexicographic order. Finally we convert the set to a list and return it.
#include <iostream>
#include <set>
#include <string>
#include <vector>
using namespace std;
bool isVowel(char ch)
{
return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u';
}
void findSubsequences(int index, int n, string &s, string ¤t, set<string> &st)
{
// If we have reached the end of string check if valid subsequence
if (index == n)
{
// Add if non empty starts with vowel and ends with consonant
if (!current.empty() && isVowel(current[0]) && !isVowel(current.back()))
st.insert(current);
return;
}
// Include current character and recurse
current.push_back(s[index]);
findSubsequences(index + 1, n, s, current, st);
// Exclude current character and recurse
current.pop_back();
findSubsequences(index + 1, n, s, current, st);
}
vector<string> findSubseq(string s)
{
int n = s.length();
string current = "";
set<string> st;
// Find all valid subsequences using recursion
findSubsequences(0, n, s, current, st);
// Convert set to vector for return
return vector<string>(st.begin(), st.end());
}
int main()
{
string s = "abc";
vector<string> result = findSubseq(s);
for (int i = 0; i < result.size(); i++)
{
if (i != 0)
cout << " ";
cout << result[i];
}
cout << endl;
return 0;
}
import java.util.ArrayList;
import java.util.TreeSet;
class GFG {
static boolean isVowel(char ch) {
return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u';
}
static void findSubsequences(int index, int n, String s, StringBuilder current, TreeSet<String> st) {
// If we have reached the end of string check if valid subsequence
if (index == n) {
// Add if non empty starts with vowel and ends with consonant
String curr = current.toString();
if (!curr.isEmpty() && isVowel(curr.charAt(0)) && !isVowel(curr.charAt(curr.length() - 1)))
st.add(curr);
return;
}
// Include current character and recurse
current.append(s.charAt(index));
findSubsequences(index + 1, n, s, current, st);
// Exclude current character and recurse
current.deleteCharAt(current.length() - 1);
findSubsequences(index + 1, n, s, current, st);
}
static ArrayList<String> findSubseq(String s) {
int n = s.length();
StringBuilder current = new StringBuilder();
TreeSet<String> st = new TreeSet<>();
// Find all valid subsequences using recursion
findSubsequences(0, n, s, current, st);
// Convert TreeSet to ArrayList for return
return new ArrayList<>(st);
}
public static void main(String[] args) {
String s = "abc";
ArrayList<String> result = findSubseq(s);
System.out.println(String.join(" ", result));
}
}
def isVowel(ch):
return ch in 'aeiou'
def findSubsequences(index, n, s, current, st):
# If we have reached the end of string check if valid subsequence
if index == n:
# Add if non empty starts with vowel and ends with consonant
if current and isVowel(current[0]) and not isVowel(current[-1]):
st.add(current)
return
# Include current character and recurse
findSubsequences(index + 1, n, s, current + s[index], st)
# Exclude current character and recurse
findSubsequences(index + 1, n, s, current, st)
def findSubseq(s):
n = len(s)
st = set()
# Find all valid subsequences using recursion
findSubsequences(0, n, s, "", st)
# Convert set to sorted list for return
return sorted(st)
if __name__ == "__main__":
s = "abc"
result = findSubseq(s)
print(' '.join(result))
using System;
using System.Collections.Generic;
class GFG {
static bool isVowel(char ch) {
return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u';
}
static void findSubsequences(int index, int n, string s, string current, SortedSet<string> st) {
// If we have reached the end of string check if valid subsequence
if (index == n) {
// Add if non empty starts with vowel and ends with consonant
if (current.Length > 0 && isVowel(current[0]) && !isVowel(current[current.Length - 1]))
st.Add(current);
return;
}
// Include current character and recurse
findSubsequences(index + 1, n, s, current + s[index], st);
// Exclude current character and recurse
findSubsequences(index + 1, n, s, current, st);
}
static List<string> findSubseq(string s) {
int n = s.Length;
SortedSet<string> st = new SortedSet<string>();
// Find all valid subsequences using recursion
findSubsequences(0, n, s, "", st);
// Convert SortedSet to List for return
return new List<string>(st);
}
static void Main() {
string s = "abc";
List<string> result = findSubseq(s);
Console.WriteLine(string.Join(" ", result));
}
}
function isVowel(ch) {
return 'aeiou'.includes(ch);
}
function findSubsequences(index, n, s, current, st) {
// If we have reached the end of string check if valid subsequence
if (index === n) {
// Add if non empty starts with vowel and ends with consonant
if (current.length > 0 && isVowel(current[0]) && !isVowel(current[current.length - 1]))
st.add(current);
return;
}
// Include current character and recurse
findSubsequences(index + 1, n, s, current + s[index], st);
// Exclude current character and recurse
findSubsequences(index + 1, n, s, current, st);
}
function findSubseq(s) {
let n = s.length;
let st = new Set();
// Find all valid subsequences using recursion
findSubsequences(0, n, s, "", st);
// Convert set to sorted array for return
return [...st].sort();
}
// Driver code
let s = "abc";
let result = findSubseq(s);
console.log(result.join(' '));
Output
ab abc ac
[Expected Approach] Using Bit Masking - O(n * 2^n) Time and O(n * 2^n) Space
The idea is to use a bitmask to represent every possible subsequence of the string. For a string of length n there are 2^n possible subsequences. Each bit in the mask from 0 to 2^n - 1 represents whether the character at that position is included or not. For each mask we build the corresponding subsequence and check if it starts with a vowel and ends with a consonant. We use a set to handle duplicates and maintain lexicographic order automatically.
#include <iostream>
#include <set>
#include <string>
#include <vector>
using namespace std;
bool isVowel(char ch)
{
return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u';
}
vector<string> findSubseq(string s)
{
int n = s.length();
set<string> st;
// Iterate over all possible bitmasks from 1 to 2^n - 1
for (int mask = 1; mask < (1 << n); mask++)
{
string current = "";
// Build subsequence based on set bits in mask
for (int i = 0; i < n; i++)
{
if (mask & (1 << i))
current += s[i];
}
// Add if starts with vowel and ends with consonant
if (isVowel(current[0]) && !isVowel(current.back()))
st.insert(current);
}
// Convert set to vector for return
return vector<string>(st.begin(), st.end());
}
int main()
{
string s = "abc";
vector<string> result = findSubseq(s);
for (int i = 0; i < result.size(); i++)
{
if (i != 0)
cout << " ";
cout << result[i];
}
cout << endl;
return 0;
}
import java.util.ArrayList;
import java.util.TreeSet;
class GFG {
static boolean isVowel(char ch) {
return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u';
}
static ArrayList<String> findSubseq(String s) {
int n = s.length();
TreeSet<String> st = new TreeSet<>();
// Iterate over all possible bitmasks from 1 to 2^n - 1
for (int mask = 1; mask < (1 << n); mask++) {
StringBuilder current = new StringBuilder();
// Build subsequence based on set bits in mask
for (int i = 0; i < n; i++) {
if ((mask & (1 << i)) != 0)
current.append(s.charAt(i));
}
// Add if starts with vowel and ends with consonant
String curr = current.toString();
if (isVowel(curr.charAt(0)) && !isVowel(curr.charAt(curr.length() - 1)))
st.add(curr);
}
// Convert TreeSet to ArrayList for return
return new ArrayList<>(st);
}
public static void main(String[] args) {
String s = "abc";
ArrayList<String> result = findSubseq(s);
System.out.println(String.join(" ", result));
}
}
def isVowel(ch):
return ch in 'aeiou'
def findSubseq(s):
n = len(s)
st = set()
# Iterate over all possible bitmasks from 1 to 2^n - 1
for mask in range(1, 1 << n):
current = ""
# Build subsequence based on set bits in mask
for i in range(n):
if mask & (1 << i):
current += s[i]
# Add if starts with vowel and ends with consonant
if isVowel(current[0]) and not isVowel(current[-1]):
st.add(current)
# Convert set to sorted list for return
return sorted(st)
if __name__ == "__main__":
s = "abc"
result = findSubseq(s)
print(' '.join(result))
using System;
using System.Collections.Generic;
class GFG {
static bool isVowel(char ch) {
return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u';
}
static List<string> findSubseq(string s) {
int n = s.Length;
SortedSet<string> st = new SortedSet<string>();
// Iterate over all possible bitmasks from 1 to 2^n - 1
for (int mask = 1; mask < (1 << n); mask++) {
string current = "";
// Build subsequence based on set bits in mask
for (int i = 0; i < n; i++) {
if ((mask & (1 << i)) != 0)
current += s[i];
}
// Add if starts with vowel and ends with consonant
if (isVowel(current[0]) && !isVowel(current[current.Length - 1]))
st.Add(current);
}
// Convert SortedSet to List for return
return new List<string>(st);
}
static void Main() {
string s = "abc";
List<string> result = findSubseq(s);
Console.WriteLine(string.Join(" ", result));
}
}
function isVowel(ch) {
return 'aeiou'.includes(ch);
}
function findSubseq(s) {
let n = s.length;
let st = new Set();
// Iterate over all possible bitmasks from 1 to 2^n - 1
for (let mask = 1; mask < (1 << n); mask++) {
let current = "";
// Build subsequence based on set bits in mask
for (let i = 0; i < n; i++) {
if (mask & (1 << i))
current += s[i];
}
// Add if starts with vowel and ends with consonant
if (isVowel(current[0]) && !isVowel(current[current.length - 1]))
st.add(current);
}
// Convert set to sorted array for return
return [...st].sort();
}
// Driver code
let s = "abc";
let result = findSubseq(s);
console.log(result.join(' '));
Output
ab abc ac