Given three non-negative integers, X, Y, and K, the task is to find the Kth smallest lexicographical string having X occurrences of character ‘a’ and Y occurrences of character ‘b’.
Examples:
Input: X = 2, Y = 3, K = 3
Output: abbab
Explanation:
First lexicographical smallest string = “aabbb”.
Second lexicographical smallest string = “ababb”.
Third lexicographical smallest string = “abbab”.Input: X = 4, Y = 3, K = 4
Output: aaabbba
Naive Approach: The simplest approach is to generate all distinct permutations of the string X occurrences of character ‘a’ and Y occurrences of character ‘b’. Then first, sort the output string array in lexicographical order and print the Kth index string.
Time complexity: O(N*N!), where N is (X + Y)
Auxiliary Space: O(N!)
Efficient Approach: This problem has Overlapping Subproblems property and Optimal Substructure property. So this problem can be solved using Dynamic Programming. Like other typical Dynamic Programming(DP) problems, recomputation of the same subproblems can be avoided by constructing a temporary array that stores the results of subproblems. Follow the steps below to solve this problem.
- Initialize a 2D array, dp[][] where dp[i][j] denotes the number of strings containing i number of a’s, and j number of b’s.
-
Iterate in the range [0, X] using the variable i:
-
Iterate in the range [0, Y] using the variable j:
- If i is greater than 0, then update dp[i][j] to dp[i][j] + dp[i-1][j].
- If j is greater than 0, then update dp[i][j] to dp[i][j] + dp[i][j-1].
-
Iterate in the range [0, Y] using the variable j:
- Now, recursively find the Kth lexicographical smallest string by calling the function kthString(int X, int Y, int K).
- Handle the base cases:
- If there are only ‘a’ characters present then return a string of all ‘a’ characters.
- If there are only ‘b’ characters present then return a string of all ‘b’ characters.
- If there are more than or equal to K strings that start with ‘a’, then return “a” + kthString(X-1, Y, K).
- Else the first character of the resultant string is ‘b’, return “b” + kthString(X, Y-1, K – dp[X-1][Y]).
Below is the implementation of the above approach:
// C++ program for the above approach #include <bits/stdc++.h> using namespace std;
const int MAX = 30;
// Function to fill dp array void findNumString( int X, int Y, int dp[][MAX])
{ // Initialize all the entries with 0
for ( int i = 0; i < MAX; i++) {
for ( int j = 0; j < MAX; j++) {
dp[i][j] = 0;
}
}
// Update dp[0][0] to 1
dp[0][0] = 1;
// Traverse the dp array
for ( int i = 0; i <= X; ++i) {
for ( int j = 0; j <= Y; ++j) {
// Update the value of dp[i][j]
if (i > 0) {
dp[i][j] += dp[i - 1][j];
}
if (j > 0) {
dp[i][j] += dp[i][j - 1];
}
}
}
} // Recursive function to find the Kth // lexicographical smallest string string kthString( int X, int Y, int K, int dp[][MAX])
{ // Handle the base cases
if (X == 0) {
return string(Y, 'b' );
}
if (Y == 0) {
return string(X, 'a' );
}
// If there are more than or equal
// to K strings which start with a,
// then the first character is 'a'
if (K <= dp[X - 1][Y]) {
return string( "a" ) + kthString(X - 1, Y, K, dp);
}
// Otherwise the first character
// of the resultant string is 'b'
else {
return string( "b" )
+ kthString(X, Y - 1,
K - dp[X - 1][Y], dp);
}
} // Function to find the Kth // lexicographical smallest string void kthStringUtil( int X, int Y, int K)
{ int dp[MAX][MAX];
// Function call to fill the dp array
findNumString(X, Y, dp);
// Print the resultant string
cout << kthString(X, Y, K, dp) << '\n' ;
} // Driver Code int main()
{ // Given Input
int X = 4;
int Y = 3;
int K = 4;
// Function Call
kthStringUtil(X, Y, K);
return 0;
} |
// Java program for the above approach public class GFG
{ static int MAX = 30 ;
// Function to fill dp array static void findNumString( int X, int Y, int dp[][])
{ // Initialize all the entries with 0
for ( int i = 0 ; i < MAX; i++) {
for ( int j = 0 ; j < MAX; j++) {
dp[i][j] = 0 ;
}
}
// Update dp[0][0] to 1
dp[ 0 ][ 0 ] = 1 ;
// Traverse the dp array
for ( int i = 0 ; i <= X; ++i) {
for ( int j = 0 ; j <= Y; ++j) {
// Update the value of dp[i][j]
if (i > 0 ) {
dp[i][j] += dp[i - 1 ][j];
}
if (j > 0 ) {
dp[i][j] += dp[i][j - 1 ];
}
}
}
} // Recursive function to find the Kth // lexicographical smallest string static String kthString( int X, int Y, int K, int dp[][])
{ // Handle the base cases
String x1 = "" ;
String y1 = "" ;
for ( int i= 0 ;i<Y;i++){
x1 += 'b' ;
}
for ( int i= 0 ;i<X;i++){
y1 += 'a' ;
}
if (X == 0 )
return x1;
if (Y == 0 )
return y1;
// If there are more than or equal
// to K strings which start with a,
// then the first character is 'a'
if (K <= dp[X - 1 ][Y]) {
return ( "a" + kthString(X - 1 , Y, K, dp));
}
// Otherwise the first character
// of the resultant string is 'b'
else {
return ( "b" + kthString(X, Y - 1 , K - dp[X - 1 ][Y], dp));
}
} // Function to find the Kth // lexicographical smallest string static void kthStringUtil( int X, int Y, int K)
{ int dp[][] = new int [MAX][MAX];
// Function call to fill the dp array
findNumString(X, Y, dp);
// Print the resultant string
System.out.println(kthString(X, Y, K, dp));
} // Driver Code public static void main(String args[])
{ // Given Input
int X = 4 ;
int Y = 3 ;
int K = 4 ;
// Function Call
kthStringUtil(X, Y, K);
}
} // This code is contributed by SoumikMondal |
# Python3 program for the above approach from typing import Mapping
MAX = 30
# Function to fill dp array def findNumString(X, Y, dp):
# Initialize all the entries with 0
for i in range ( 0 , MAX ):
for j in range ( 0 , MAX ):
dp[i][j] = 0
# Update dp[0][0] to 1
dp[ 0 ][ 0 ] = 1
# Traverse the dp array
for i in range ( 0 , X + 1 ):
for j in range ( 0 , Y + 1 ):
# Update the value of dp[i][j]
if (i > 0 ):
dp[i][j] + = dp[i - 1 ][j]
if (j > 0 ):
dp[i][j] + = dp[i][j - 1 ]
# Recursive function to find the Kth # lexicographical smallest string def kthString(X, Y, K, dp):
# Handle the base cases
x1 = ""
y1 = ""
for i in range ( 0 , Y):
x1 + = 'b'
for i in range ( 0 , X):
y1 + = 'a'
if (X = = 0 ):
return x1
if (Y = = 0 ):
return y1
# If there are more than or equal
# to K strings which start with a,
# then the first character is 'a'
if (K < = dp[X - 1 ][Y]):
return "a" + kthString(X - 1 , Y, K, dp)
# Otherwise the first character
# of the resultant string is 'b'
else :
return "b" + kthString(X, Y - 1 ,
K - dp[X - 1 ][Y], dp)
# Function to find the Kth # lexicographical smallest string def kthStringUtil(X, Y, K):
dp = [[ 0 for i in range ( MAX )]
for col in range ( MAX )]
# Function call to fill the dp array
findNumString(X, Y, dp)
# Print the resultant
print (kthString(X, Y, K, dp))
# Driver Code # Given Input X = 4
Y = 3
K = 4
# Function Call kthStringUtil(X, Y, K) # This code is contributed by amreshkumar3 |
// C# program for the above approach using System;
class GFG{
static int MAX = 30;
// Function to fill dp array static void findNumString( int X, int Y, int [,] dp)
{ // Initialize all the entries with 0
for ( int i = 0; i < MAX; i++) {
for ( int j = 0; j < MAX; j++) {
dp[i, j] = 0;
}
}
// Update dp[0][0] to 1
dp[0, 0] = 1;
// Traverse the dp array
for ( int i = 0; i <= X; ++i) {
for ( int j = 0; j <= Y; ++j) {
// Update the value of dp[i][j]
if (i > 0) {
dp[i, j] += dp[i - 1, j];
}
if (j > 0) {
dp[i, j] += dp[i, j - 1];
}
}
}
} // Recursive function to find the Kth // lexicographical smallest string static string kthString( int X, int Y, int K, int [,] dp)
{ // Handle the base cases
string x1 = "" ;
string y1 = "" ;
for ( int i=0;i<Y;i++){
x1 += 'b' ;
}
for ( int i=0;i<X;i++){
y1 += 'a' ;
}
if (X == 0)
return x1;
if (Y == 0)
return y1;
// If there are more than or equal
// to K strings which start with a,
// then the first character is 'a'
if (K <= dp[X - 1, Y]) {
return ( "a" + kthString(X - 1, Y, K, dp));
}
// Otherwise the first character
// of the resultant string is 'b'
else {
return ( "b" + kthString(X, Y - 1, K - dp[X - 1, Y], dp));
}
} // Function to find the Kth // lexicographical smallest string static void kthStringUtil( int X, int Y, int K)
{ int [,] dp = new int [MAX, MAX];
// Function call to fill the dp array
findNumString(X, Y, dp);
// Print the resultant string
Console.WriteLine(kthString(X, Y, K, dp));
} // Driver code static void Main()
{ // Given Input
int X = 4;
int Y = 3;
int K = 4;
// Function Call
kthStringUtil(X, Y, K);
} } // This code is contributed by code_hunt. |
<script> // JavaScript program for the above approach const MAX = 30 // Function to fill dp array function findNumString(X, Y, dp){
// Initialize all the entries with 0
for (let i = 0; i < MAX; i++)
for (let j = 0; j < MAX; j++)
dp[i][j] = 0
// Update dp[0][0] to 1
dp[0][0] = 1
// Traverse the dp array
for (let i = 0; i < X + 1; i++)
{
for (let j = 0; j < Y + 1; j++)
{
// Update the value of dp[i][j]
if (i > 0)
dp[i][j] += dp[i - 1][j]
if (j > 0)
dp[i][j] += dp[i][j - 1]
}
}
} // Recursive function to find the Kth // lexicographical smallest string function kthString(X, Y, K, dp){
// Handle the base cases
let x1 = ""
let y1 = ""
for (let i = 0; i < Y; i++)
x1 += 'b'
for (let i = 0; i < X; i++)
y1 += 'a'
if (X == 0)
return x1
if (Y == 0)
return y1
// If there are more than or equal
// to K strings which start with a,
// then the first character is 'a'
if (K <= dp[X - 1][Y])
return "a" + kthString(X - 1, Y, K, dp)
// Otherwise the first character
// of the resultant string is 'b'
else
return "b" + kthString(X, Y - 1,
K - dp[X - 1][Y], dp)
} // Function to find the Kth // lexicographical smallest string function kthStringUtil(X, Y, K)
{ let dp = new Array(MAX);
for (let i = 0; i < MAX; i++)
{
dp[i] = new Array(MAX);
}
// Function call to fill the dp array
findNumString(X, Y, dp)
// Print the resultant
document.write(kthString(X, Y, K, dp), "</br>" )
} // Driver Code // Given Input let X = 4 let Y = 3 let K = 4 // Function Call kthStringUtil(X, Y, K) // This code is contributed by shinjanpatra </script> |
aaabbba
Time Complexity: O(X*Y)
Auxiliary Space: O(X*Y)
Efficient Approach: The above approach can further be optimized by iteratively implementing the KthString function. Follow the steps below to solve this problem:
- Declare a 2D array, dp where dp[i][j] denotes the number of strings containing i number of a’s, and j number of b’s.
-
Iterate in the range [0, X] using the variable i:
-
Iterate in the range [0, Y] using the variable j:
- If i is greater than 0, then update dp[i][j] to dp[i][j] + dp[i-1][j].
- If j is greater than 0, then update dp[i][j] to dp[i][j] + dp[i][j-1].
-
Iterate in the range [0, Y] using the variable j:
- Now, iteratively find the Kth lexicographical smallest string.
-
Traverse while X is greater than 0 and Y is greater than 0:
- If there are more than or equal to K strings that start with ‘a’, then print ‘a’ and decrement X by 1.
- Else, the first character of the resultant string is ‘b’, print ‘b’, and decrement Y by 1.
- If there are only ‘a’ characters present then print a string of all ‘a‘ characters.
- If there are only ‘b‘ characters present then print a string of all ‘b‘ characters.
Below is the implementation of the above approach:
// C++ program for the above approach #include <bits/stdc++.h> using namespace std;
const int MAX = 30;
// Function to fill dp array void findNumString( int X, int Y, int dp[][MAX])
{ // Initialize all the entries with 0
for ( int i = 0; i < MAX; i++) {
for ( int j = 0; j < MAX; j++) {
dp[i][j] = 0;
}
}
// Update dp[0][0] to 1
dp[0][0] = 1;
// Traverse the dp array
for ( int i = 0; i <= X; ++i) {
for ( int j = 0; j <= Y; ++j) {
// Update the value of dp[i][j]
if (i > 0) {
dp[i][j] += dp[i - 1][j];
}
if (j > 0) {
dp[i][j] += dp[i][j - 1];
}
}
}
} // Iterative function to find the Kth // lexicographical smallest string void kthString( int X, int Y, int K, int dp[][MAX])
{ while (X > 0 and Y > 0) {
// If there are more than or
// equal to K strings which start
// with a, then print 'a'
if (K <= dp[X - 1][Y]) {
cout << 'a' ;
X -= 1;
}
// Otherwise the first character
// of the resultant string is b
else {
K -= dp[X - 1][Y];
cout << 'b' ;
Y -= 1;
}
}
// If there are only 'a' characters
// present then print a string of
// all 'a' characters
cout << string(X, 'a' );
// If there are only 'b' characters
// present then print a string of
// all 'b' characters
cout << string(Y, 'b' );
cout << '\n' ;
} // Function to find the Kth // lexicographical smallest string void kthStringUtil( int X, int Y, int K)
{ int dp[MAX][MAX];
// Function call to fill the dp array
findNumString(X, Y, dp);
// Function call to find the
// required string
kthString(X, Y, K, dp);
} // Driver Code int main()
{ // Given Input
int X = 4;
int Y = 3;
int K = 4;
// Function Call
kthStringUtil(X, Y, K);
return 0;
} |
// Java code for the above approach import java.io.*;
class Main {
static final int MAX = 30 ;
// Function to fill dp array
static void findNumString( int X, int Y, int [][] dp) {
// Initialize all the entries with 0
for ( int i = 0 ; i < MAX; i++) {
for ( int j = 0 ; j < MAX; j++) {
dp[i][j] = 0 ;
}
}
// Update dp[0][0] to 1
dp[ 0 ][ 0 ] = 1 ;
// Traverse the dp array
for ( int i = 0 ; i <= X; ++i) {
for ( int j = 0 ; j <= Y; ++j) {
// Update the value of dp[i][j]
if (i > 0 ) {
dp[i][j] += dp[i - 1 ][j];
}
if (j > 0 ) {
dp[i][j] += dp[i][j - 1 ];
}
}
}
}
// Iterative function to find the Kth
// lexicographical smallest string
static void kthString( int X, int Y, int K, int [][] dp) {
while (X > 0 && Y > 0 ) {
// If there are more than or
// equal to K strings which start
// with a, then print 'a'
if (K <= dp[X - 1 ][Y]) {
System.out.print( "a" );
X -= 1 ;
}
// Otherwise the first character
// of the resultant string is b
else {
K -= dp[X - 1 ][Y];
System.out.print( "b" );
Y -= 1 ;
}
}
// If there are only 'a' characters
// present then print a string of
// all 'a' characters
for ( int i = 0 ; i < X; i++) {
System.out.print( "a" );
}
// If there are only 'b' characters
// present then print a string of
// all 'b' characters
for ( int i = 0 ; i < Y; i++) {
System.out.print( "b" );
}
System.out.println();
}
// Function to find the Kth
// lexicographical smallest string
static void kthStringUtil( int X, int Y, int K) {
int [][] dp = new int [MAX][MAX];
// Function call to fill the dp array
findNumString(X, Y, dp);
// Function call to find the
// required string
kthString(X, Y, K, dp);
}
// Driver Code
public static void main(String[] args) {
// Given Input
int X = 4 ;
int Y = 3 ;
int K = 4 ;
// Function Call
kthStringUtil(X, Y, K);
}
} // This code is contributed by lokeshpotta20. |
# Python3 program for the above approach MAX = 30 ;
# Function to fill dp array def find_num_string(X, Y, dp):
# Initialize all the entries with 0
for i in range ( MAX ):
for j in range ( MAX ):
dp[i][j] = 0
# Update dp[0][0] to 1
dp[ 0 ][ 0 ] = 1
# Traverse the dp array
for i in range (X + 1 ):
for j in range (Y + 1 ):
# Update the value of dp[i][j]
if i > 0 :
dp[i][j] + = dp[i - 1 ][j]
if j > 0 :
dp[i][j] + = dp[i][j - 1 ]
# Iterative function to find the Kth # lexicographical smallest string def kth_string(X, Y, K, dp):
while X > 0 and Y > 0 :
# If there are more than or
# equal to K strings which start
# with a, then print 'a'
if K < = dp[X - 1 ][Y]:
print ( 'a' , end = '')
X - = 1
# Otherwise the first character
# of the resultant string is b
else :
K - = dp[X - 1 ][Y]
print ( 'b' , end = '')
Y - = 1
# If there are only 'a' characters
# present then print a string of
# all 'a' characters
print ( 'a' * X, end = '')
# If there are only 'b' characters
# present then print a string of
# all 'b' characters
print ( 'b' * Y)
# Function to find the Kth # lexicographical smallest string def kth_string_util(X, Y, K):
dp = [[ 0 for j in range ( MAX )] for i in range ( MAX )]
# Function call to fill the dp array
find_num_string(X, Y, dp)
# Function call to find the required string
kth_string(X, Y, K, dp)
# Driver Code if __name__ = = '__main__' :
# Given Input
X = 4
Y = 3
K = 4
# Function Call
kth_string_util(X, Y, K)
# This code is contributed by ik_9 |
// C# program to implement above approach using System;
using System.Collections.Generic;
class GFG
{ static int MAX = 30;
// Function to fill dp array
static void findNumString( int X, int Y, int [][] dp)
{
// Initialize all the entries with 0
for ( int i = 0 ; i < MAX ; i++) {
for ( int j = 0 ; j < MAX ; j++) {
dp[i][j] = 0;
}
}
// Update dp[0][0] to 1
dp[0][0] = 1;
// Traverse the dp array
for ( int i = 0 ; i <= X ; ++i) {
for ( int j = 0 ; j <= Y ; ++j) {
// Update the value of dp[i][j]
if (i > 0) {
dp[i][j] += dp[i - 1][j];
}
if (j > 0) {
dp[i][j] += dp[i][j - 1];
}
}
}
}
// Iterative function to find the Kth
// lexicographical smallest string
static void kthString( int X, int Y, int K, int [][] dp)
{
while (X > 0 && Y > 0) {
// If there are more than or
// equal to K strings which start
// with a, then print 'a'
if (K <= dp[X - 1][Y]) {
Console.Write( 'a' );
X -= 1;
}
// Otherwise the first character
// of the resultant string is b
else {
K -= dp[X - 1][Y];
Console.Write( 'b' );
Y -= 1;
}
}
// If there are only 'a' characters
// present then print a string of
// all 'a' characters
String ans = "" ;
for ( int i = 0 ; i < X ; i++){
ans+= "a" ;
}
Console.Write(ans);
ans = "" ;
// If there are only 'b' characters
// present then print a string of
// all 'b' characters
for ( int i = 0 ; i < Y ; i++){
ans+= "b" ;
}
Console.Write(ans);
Console.Write( "\n" );
}
// Function to find the Kth
// lexicographical smallest string
static void kthStringUtil( int X, int Y, int K)
{
int [][] dp = new int [MAX][];
for ( int i = 0 ; i < MAX ; i++){
dp[i] = new int [MAX];
}
// Function call to fill the dp array
findNumString(X, Y, dp);
// Function call to find the
// required string
kthString(X, Y, K, dp);
}
// Driver Code
public static void Main( string [] args){
// Given Input
int X = 4;
int Y = 3;
int K = 4;
// Function Call
kthStringUtil(X, Y, K);
}
} // This code is contributed by subhamgoyal2014. |
// Javascript program for the above approach const MAX = 30; // Function to fill dp array function findNumString( X, Y, dp)
{ // Initialize all the entries with 0
for (let i = 0; i < MAX; i++) {
for (let j = 0; j < MAX; j++) {
dp[i][j] = 0;
}
}
// Update dp[0][0] to 1
dp[0][0] = 1;
// Traverse the dp array
for (let i = 0; i <= X; ++i) {
for (let j = 0; j <= Y; ++j) {
// Update the value of dp[i][j]
if (i > 0) {
dp[i][j] += dp[i - 1][j];
}
if (j > 0) {
dp[i][j] += dp[i][j - 1];
}
}
}
} // Iterative function to find the Kth // lexicographical smallest string function kthString( X, Y, K, dp)
{ while (X > 0 && Y > 0) {
// If there are more than or
// equal to K strings which start
// with a, then print 'a'
if (K <= dp[X - 1][Y]) {
document.write( 'a' );
X -= 1;
}
// Otherwise the first character
// of the resultant string is b
else {
K -= dp[X - 1][Y];
document.write( 'b' );
Y -= 1;
}
}
// If there are only 'a' characters
// present then print a string of
// all 'a' characters
let ans = "" ;
for (let i = 0 ; i < X ; i++){
ans+= "a" ;
}
document.write(ans);
ans = "" ;
// If there are only 'b' characters
// present then print a string of
// all 'b' characters
for (let i = 0 ; i < Y ; i++){
ans+= "b" ;
}
document.write(ans);
} // Function to find the Kth // lexicographical smallest string function kthStringUtil( X, Y, K)
{ let dp= new Array(MAX);
for (let i=0; i<MAX; i++)
dp[i]= new Array(MAX);
// Function call to fill the dp array
findNumString(X, Y, dp);
// Function call to find the
// required string
kthString(X, Y, K, dp);
} // Driver Code // Given Input let X = 4; let Y = 3; let K = 4; // Function Call kthStringUtil(X, Y, K); |
aaabbba
Time Complexity: O(X*Y)
Auxiliary Space: O(X*Y)