Skip to content
Related Articles

Related Articles

Improve Article

Lexicographically Kth-smallest string having ‘a’ X times and ‘b’ Y times

  • Last Updated : 12 Jul, 2021

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].
  • 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++




// 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




// 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




# 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#




// 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.
Output: 
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].
  • 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++




// 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;
}
Output: 
aaabbba

 

Time Complexity: O(X*Y)
Auxiliary Space: O(X*Y)

 

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.




My Personal Notes arrow_drop_up
Recommended Articles
Page :