Open In App

Count lexicographically increasing K-length strings possible from first N alphabets

Given two positive integers N and K, the task is to find the number of K length strings that can be generated from the first N alphabets such that the characters in the string are sorted lexicographically.

Examples:



Input: N = 5, K = 2
Output: 15
Explanation: All possible strings are {“AA”, “AB”, “AC”, “AD”, “AE”, “BB”, “BC”, “BD”, “BE”, “CC”, “CD”, “CE”, “DD”, “DE”, “EE”}.

Input: N = 7, K = 10
Output: 8008



 

Naive Approach: The simplest approach to solve the problem is to use Recursion and Backtracking to generate all possible arrangements of characters and for each string, check if the characters follow a lexicographically increasing order or not. Print the count of all such strings.  




#include <iostream>
#include <vector>
#include <algorithm>
 
using namespace std;
 
vector<string> generateStrings(string curr_str, int curr_char, int N, int K) {
    if (curr_str.length() == K) {
        vector<string> res;
        res.push_back(curr_str);
        return res;
    }
    vector<string> res;
    for (int i = curr_char; i < N; i++) {
        vector<string> suffixes = generateStrings(curr_str + char(65 + i), i, N, K);
        res.insert(res.end(), suffixes.begin(), suffixes.end());
    }
    return res;
}
 
int countStrings(int N, int K) {
    vector<string> all_strings = generateStrings("", 0, N, K);
    vector<string> sorted_strings;
    for (int i = 0; i < all_strings.size(); i++) {
        string s = all_strings[i];
        if (is_sorted(s.begin(), s.end())) {
            sorted_strings.push_back(s);
        }
    }
    return sorted_strings.size();
}
 
int main() {
    cout << countStrings(5, 2) << endl; // expected output: 15
    cout << countStrings(7, 10) << endl; // expected output: 8008
    return 0;
}




import java.util.ArrayList;
import java.util.List;
 
public class Main {
    // Function to generate strings of length K using characters from 'A' to 'A + N - 1'
    static List<String> generateStrings(String currStr, int currChar, int N, int K) {
        if (currStr.length() == K) {
            List<String> res = new ArrayList<>();
            res.add(currStr);
            return res;
        }
        List<String> res = new ArrayList<>();
        for (int i = currChar; i < N; i++) {
            List<String> suffixes = generateStrings(currStr + (char) ('A' + i), i, N, K);
            res.addAll(suffixes);
        }
        return res;
    }
 
    // Function to count strings that are sorted lexicographically
    static int countStrings(int N, int K) {
        List<String> allStrings = generateStrings("", 0, N, K);
        List<String> sortedStrings = new ArrayList<>();
        for (String s : allStrings) {
            if (isSorted(s)) {
                sortedStrings.add(s);
            }
        }
        return sortedStrings.size();
    }
 
    // Helper function to check if a string is sorted
    static boolean isSorted(String s) {
        for (int i = 1; i < s.length(); i++) {
            if (s.charAt(i - 1) > s.charAt(i)) {
                return false;
            }
        }
        return true;
    }
 
    public static void main(String[] args) {
        System.out.println(countStrings(5, 2)); // expected output: 15
        System.out.println(countStrings(7, 10)); // expected output: 8008
    }
}




def count_strings(N, K):
    def generate_strings(curr_str, curr_char, K):
        if len(curr_str) == K:
            return [curr_str]
        res = []
        for i in range(curr_char, N):
            res.extend(generate_strings(curr_str + chr(65 + i), i, K))
        return res
     
    all_strings = generate_strings("", 0, K)
    sorted_strings = [s for s in all_strings if list(s) == sorted(list(s))]
    return len(sorted_strings)
 
# example usage
print(count_strings(5, 2)) # expected output: 15
print(count_strings(7, 10)) # expected output: 8008




using System;
using System.Collections.Generic;
 
public class SortedStringsCount
{
    // Function to generate all possible strings of length K
    static List<string> GenerateStrings(string currStr, int currChar, int N, int K)
    {
        if (currStr.Length == K)
        {
            List<string> result = new List<string>();
            result.Add(currStr);
            return result;
        }
 
        List<string> resultStrings = new List<string>();
        for (int i = currChar; i < N; i++)
        {
            List<string> suffixes = GenerateStrings(currStr + (char)('A' + i), i, N, K);
            resultStrings.AddRange(suffixes);
        }
 
        return resultStrings;
    }
 
    // Function to count sorted strings
    static int CountSortedStrings(int N, int K)
    {
        List<string> allStrings = GenerateStrings("", 0, N, K);
        List<string> sortedStrings = new List<string>();
 
        foreach (string s in allStrings)
        {
            if (IsSorted(s))
            {
                sortedStrings.Add(s);
            }
        }
 
        return sortedStrings.Count;
    }
 
    // Function to check if a string is sorted
    static bool IsSorted(string s)
    {
        for (int i = 1; i < s.Length; i++)
        {
            if (s[i] < s[i - 1])
            {
                return false;
            }
        }
        return true;
    }
 
    public static void Main(string[] args)
    {
        Console.WriteLine(CountSortedStrings(5, 2));  // Expected output: 15
        Console.WriteLine(CountSortedStrings(7, 10)); // Expected output: 8008
    }
}




function countStrings(N, K) {
  function generateStrings(currStr, currChar, K) {
    if (currStr.length === K) {
      return [currStr];
    }
    let res = [];
    for (let i = currChar; i < N; i++) {
      res.push(...generateStrings(currStr + String.fromCharCode(65 + i), i, K));
    }
    return res;
  }
 
  let allStrings = generateStrings("", 0, K);
  let sortedStrings = allStrings.filter(s => [...s].sort().join("") === s);
  return sortedStrings.length;
}
 
// example usage
console.log(countStrings(5, 2)); // expected output: 15
console.log(countStrings(7, 10)); // expected output: 8008

Output
15
8008


Time Complexity: O(KN)
Auxiliary Space: O(1)

Efficient Approach: To optimize the above approach, the idea is to use Dynamic Programming as there are overlapping subproblems that can be memoized or tabulated in the recursive calls by using an auxiliary 2D array dp[][] and calculate the value of each state in the bottom-up approach.

dp[i][j] represents the number of ways to arrange “i” length strings with the “j” distinct letters.
dp[i][j] =  dp[i][j – 1] (Choose not to start with first letter) 
                 +  dp[i – 1][j – 1] (Choose first 1 letter in string as first letter) 
                 +  dp[i – 2][j – 1] (Choose first 2 letters in string as first letter) 
                 + …. 
                 + ….               
                 + dp[0][j – 1] (Choose first i letters in string as first letter)
dp[i][j] = Sum of all values of (j-1)th column for “i” rows

Follow the steps below to solve this problem:

Below is the implementation of the above approach:




// C++ program for the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to count K-length
// strings from first N alphabets
void waysToArrangeKLengthStrings(
    int N, int K)
{
    // To keep track of column sum in dp
    int column_sum[N + 1] = { 0 }, i, j;
 
    // Auxiliary 2d dp array
    int dp[K + 1][N + 1] = { 0 };
 
    // Initialize dp[0][i] = 1 and
    // update the column_sum
    for (i = 0; i <= N; i++) {
        dp[0][i] = 1;
        column_sum[i] = 1;
    }
 
    // Iterate for K times
    for (i = 1; i <= K; i++) {
 
        // Iterate for N times
        for (j = 1; j <= N; j++) {
 
            // dp[i][j]: Stores the number
            // of ways to form i-length
            // strings consisting of j letters
            dp[i][j] += column_sum[j - 1];
 
            // Update the column_sum
            column_sum[j] += dp[i][j];
        }
    }
 
    // Print number of ways to arrange
    // K-length strings with N alphabets
    cout << dp[K][N];
}
 
// Driver Code
int main()
{
    // Given N and K
    int N = 5, K = 2;
 
    // Function Call
    waysToArrangeKLengthStrings(N, K);
 
    return 0;
}




// Java program for the above approach
import java.io.*;
import java.util.*;
   
class GFG{
   
// Function to count K-length
// strings from first N alphabets
static void waysToArrangeKLengthStrings(
    int N, int K)
{
     
    // To keep track of column sum in dp
    int[] column_sum = new int[N + 1];
    int i, j;
     
    for(i = 1; i < N + 1; i++)
    {
        column_sum[i] = 0;
    }
  
    // Auxiliary 2d dp array
    int dp[][] = new int[K + 1][N + 1];
     
    for(i = 1; i < K + 1; i++)
    {
        for(j = 1; j < N + 1; j++)
        {
            dp[i][j] = 0;
        }
    }
  
    // Initialize dp[0][i] = 1 and
    // update the column_sum
    for(i = 0; i <= N; i++)
    {
        dp[0][i] = 1;
        column_sum[i] = 1;
    }
  
    // Iterate for K times
    for(i = 1; i <= K; i++)
    {
         
        // Iterate for N times
        for(j = 1; j <= N; j++)
        {
             
            // dp[i][j]: Stores the number
            // of ways to form i-length
            // strings consisting of j letters
            dp[i][j] += column_sum[j - 1];
  
            // Update the column_sum
            column_sum[j] += dp[i][j];
        }
    }
     
    // Print number of ways to arrange
    // K-length strings with N alphabets
    System.out.print(dp[K][N]);
}
   
// Driver Code
public static void main(String[] args)
{
     
    // Given N and K
    int N = 5, K = 2;
  
    // Function Call
    waysToArrangeKLengthStrings(N, K);
}
}
   
// This code is contributed by susmitakundugoaldanga




# Python3 program for the above approach
 
# Function to count K-length
# strings from first N alphabets
def waysToArrangeKLengthStrings(N, K):
     
    # To keep track of column sum in dp
    column_sum = [0 for i in range(N + 1)]
    i = 0
    j = 0
 
    # Auxiliary 2d dp array
    dp = [[0 for i in range(N + 1)]
             for j in range(K + 1)]
              
    # Initialize dp[0][i] = 1 and
    # update the column_sum
    for i in range(N + 1):
        dp[0][i] = 1
        column_sum[i] = 1
         
    # Iterate for K times
    for i in range(1, K + 1):
         
        # Iterate for N times
        for j in range(1, N + 1):
             
            # dp[i][j]: Stores the number
            # of ways to form i-length
            # strings consisting of j letters
            dp[i][j] += column_sum[j - 1]
 
            # Update the column_sum
            column_sum[j] += dp[i][j]
 
    # Print number of ways to arrange
    # K-length strings with N alphabets
    print(dp[K][N])
 
# Driver Code
if __name__ == '__main__':
     
    # Given N and K
    N = 5
    K = 2
 
    # Function Call
    waysToArrangeKLengthStrings(N, K)
 
# This code is contributed by SURENDRA_GANGWAR




// C# program for the above approach
using System;
    
class GFG{
     
// Function to count K-length
// strings from first N alphabets
static void waysToArrangeKLengthStrings(int N,
                                        int K)
{
   
    // To keep track of column sum in dp
    int[] column_sum = new int[N + 1];
    int i, j;
      
    for(i = 1; i < N + 1; i++)
    {
        column_sum[i] = 0;
    }
   
    // Auxiliary 2d dp array
    int[,] dp = new int[K + 1, N + 1];
      
    for(i = 1; i < K + 1; i++)
    {
        for(j = 1; j < N + 1; j++)
        {
            dp[i, j] = 0;
        }
    }
   
    // Initialize dp[0][i] = 1 and
    // update the column_sum
    for(i = 0; i <= N; i++)
    {
        dp[0, i] = 1;
        column_sum[i] = 1;
    }
   
    // Iterate for K times
    for(i = 1; i <= K; i++)
    {
          
        // Iterate for N times
        for(j = 1; j <= N; j++)
        {
              
            // dp[i][j]: Stores the number
            // of ways to form i-length
            // strings consisting of j letters
            dp[i, j] += column_sum[j - 1];
   
            // Update the column_sum
            column_sum[j] += dp[i, j];
        }
    }
      
    // Print number of ways to arrange
    // K-length strings with N alphabets
    Console.Write(dp[K, N]);
}
  
// Driver Code
public static void Main()
{
   
    // Given N and K
    int N = 5, K = 2;
   
    // Function Call
    waysToArrangeKLengthStrings(N, K);
}
}
 
// This code is contributed by code_hunt




<script>
 
// Javascript program to implement
// the above approach
 
// Function to count K-length
// strings from first N alphabets
function waysToArrangeKLengthStrings(N, K)
{
      
    // To keep track of column sum in dp
    let column_sum = [];
    let i, j;
      
    for(i = 1; i < N + 1; i++)
    {
        column_sum[i] = 0;
    }
   
    // Auxiliary 2d dp array
    let dp = new Array(K + 1);
    // Loop to create 2D array using 1D array
    for (i = 0; i < dp.length; i++) {
        dp[i] = new Array(2);
    }
      
    for(i = 1; i < K + 1; i++)
    {
        for(j = 1; j < N + 1; j++)
        {
            dp[i][j] = 0;
        }
    }
   
    // Initialize dp[0][i] = 1 and
    // update the column_sum
    for(i = 0; i <= N; i++)
    {
        dp[0][i] = 1;
        column_sum[i] = 1;
    }
   
    // Iterate for K times
    for(i = 1; i <= K; i++)
    {
          
        // Iterate for N times
        for(j = 1; j <= N; j++)
        {
              
            // dp[i][j]: Stores the number
            // of ways to form i-length
            // strings consisting of j letters
            dp[i][j] += column_sum[j - 1];
   
            // Update the column_sum
            column_sum[j] += dp[i][j];
        }
    }
      
    // Print number of ways to arrange
    // K-length strings with N alphabets
    document.write(dp[K][N]);
}
 
    // Driver Code
     
    // Given N and K
    let N = 5, K = 2;
   
    // Function Call
    waysToArrangeKLengthStrings(N, K);
 
// This code is contributed by splevel62.
</script>

Output
15


Time Complexity: O(N*K)
Auxiliary Space: O(N*K)


Article Tags :