Open In App

Smallest Greater (than S) String of length K whose letters are subset of S

Last Updated : 20 Mar, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a string S of length N consisting of lowercase English letters and an integer K. Find the lexicographically smallest string T of length K, such that its set of letters is a subset of the set of letters of S and T is lexicographically greater than S. Note: The set of letters is a set, not a multiset. For example, the set of letters of abadaba is {a, b, d}.
Examples:

 Input : S = “abc”, K = 3 
Output : T = “aca” 
Explanation: The list of strings T of length 3, such that the set of letters of T is a subset of letters of S is as follows: “aaa”, “aab”, “aac”, “aba”, “abb”, “abc”, “aca”, “acb”, …. Among them, those which are lexicographically greater than “abc”: 
“aca”, “acb”, …. Out of those the lexicographically smallest is “aca”.

Input : S = “abc”, K = 2 
Output : T = “ac”

A simple solution is to one by on try all strings of length k in increasing order. For every string, check if it is greater than S, if yes, then return it.
Below is an efficient method to solve this problem.
Let’s consider two cases: 
1. If N < K: For this case, we can simply copy the string S to string T for upto N characters and for the remaining (K – N) characters we can append the minimum character (least ASCII value) in string S to string T (K – N) times since we have to find the lexicographically smallest string which is just greater than string S.
2. If N ? K: For this case, we need to copy the string S to string T for upto K characters and then for string T by iterating in reverse direction we have to replace all those characters by some character until the string T becomes the lexicographically smallest string greater than string S. For this we can do the following: 
 

  1. Store the characters of string S in a STL set (ofcourse, in sorted order)
  2. Copy the string S to string T upto K characters.
  3. Iterating in reverse direction, find a character (let it be found at position ‘p’) for which there exists some character having greater ASCII value in the set.
  4. Replace this character with that found in the set.
  5. Replace all characters with minimum character after (p + 1)th index upto Kth index.

Illustration: Let S = “bcegikmyyy”, N = 10, K = 9. Set = { b, c, e, g, i, k, m, y }. Copy string S to T upto K characters T = “bcegikmyy”. Then iterating in reverse direction, we first have ‘y’ but there is no greater character than ‘y’ in the set so move ahead. Again we have ‘y’, move ahead now we have ‘m’ for which there is a greater character ‘y’ in the set. Replace ‘m’ with ‘y’ and then after ‘m’ in forward direction replace all characters with minimum character i.e. ‘b’. Hence the string T becomes T = “bcegikybb”;
 

CPP




/* CPP Program to find the lexicographically
smallest string T greater than S whose
letters are subset of letters of S */
#include <bits/stdc++.h>
 
using namespace std;
 
// function to find the lexicographically
// smallest string greater than S
string findString(string S, int N, int K)
{
    // stores minimum character
    char minChar = 'z';
 
    // stores unique characters of
    // string in sorted order
    set<char> found;
 
    // Loop through to find the minimum character
    // and stores characters in the set
    for (int i = 0; i < N; i++) {
        found.insert(S[i]);
        if (S[i] < minChar)
            minChar = S[i];
    }
 
    string T;
 
    // Case 1: If N < K
    if (N < K) {
 
        // copy the string S upto N characters
        T = S;
 
        // append minChar to make the remaining
        // characters
        for (int i = 0; i < (K - N); i++)
            T += minChar;
    }
 
    // Case 2 : If N >= K
    else {
        T = "";
 
        // copy the string S upto K characters
        for (int i = 0; i < K; i++)
            T += S[i];
 
        int i;
 
        // an iterator to the set
        set<char>::iterator it;
 
        // iterating in reverse direction
        for (i = K - 1; i >= 0; i--) {
 
            // find the current character in the set
            it = found.find(T[i]);
 
            // increment the iterator
            it++;
 
            // check if some bigger character exists in set
            if (it != found.end())
                break;
        }
 
        // Replace current character with that found in set
        T[i] = *it;
 
        // Replace all characters after with minChar
        for (int j = i + 1; j < K; j++)
            T[j] = minChar;
    }
 
    return T;
}
 
// Driver Code to test the above function
int main()
{
    string S = "abc";
    int N = S.length();
 
    // Length of required string
    int K = 3;
 
    string T = findString(S, N, K);
    cout << "Lexicographically Smallest String "
            "greater than " << S
        << " is " << T << endl;
    return 0;
}


Java




import java.util.*;
 
public class LexicographicallySmallest {
    // function to find the lexicographically
    // smallest string greater than S
    public static String findString(String S, int N, int K) {
        // stores minimum character
        char minChar = 'z';
 
        // stores unique characters of
        // string in sorted order
        Set<Character> found = new HashSet<>();
 
        // Loop through to find the minimum character
        // and stores characters in the set
        for (int i = 0; i < N; i++) {
            found.add(S.charAt(i));
            if (S.charAt(i) < minChar) {
                minChar = S.charAt(i);
            }
        }
 
        StringBuilder T = new StringBuilder();
 
        // Case 1: If N < K
        if (N < K) {
            // copy the string S upto N characters
            T.append(S);
 
            // append minChar to make the remaining
            // characters
            for (int i = 0; i < K - N; i++) {
                T.append(minChar);
            }
        }
 
        // Case 2 : If N >= K
        else {
            T = new StringBuilder();
 
            // copy the string S upto K characters
            for (int i = 0; i < K; i++) {
                T.append(S.charAt(i));
            }
 
            // iterating in reverse direction
            int i;
            for (i = K - 1; i >= 0; i--) {
                // find the current character in the set
                if (found.contains(T.charAt(i))) {
                    char it = T.charAt(i);
                    // increment the iterator
                    it = (char)(it + 1);
                    // check if some bigger character exists in set
                    if (found.contains(it)) {
                        break;
                    }
                }
            }
 
            // Replace current character with that found in set
            char[] charArray = T.toString().toCharArray();
            charArray[i] = (char)(charArray[i] + 1);
            T = new StringBuilder(String.valueOf(charArray));
 
            // Replace all characters after with minChar
            for (int j = i + 1; j < K; j++) {
                T.setCharAt(j, minChar);
            }
        }
 
        return T.toString();
    }
 
    // Driver Code to test the above function
    public static void main(String[] args) {
        String S = "abc";
        int N = S.length();
 
        // Length of required string
        int K = 3;
 
        String T = findString(S, N, K);
        System.out.println("Lexicographically Smallest String greater than "
                            + S + " is " + T);
    }
}


Python3




''' Python 3 Program to find the lexicographically
smallest string T greater than S whose
letters are subset of letters of S '''
 
# function to find the lexicographically
# smallest string greater than S
def findString(S,  N,  K):
 
    # stores minimum character
    minChar = 'z'
 
    # stores unique characters of
    # string in sorted order
    found = set([])
 
    # Loop through to find the minimum character
    # and stores characters in the set
    for i in range(N):
        found.add(S[i])
        if (S[i] < minChar):
            minChar = S[i]
 
    T = ""
 
    # Case 1: If N < K
    if (N < K):
        # copy the string S upto N characters
        T = S
 
        # append minChar to make the remaining
        # characters
        for i in range((K - N)):
            T += minChar
 
    # Case 2 : If N >= K
    else:
        T = ""
 
        # copy the string S upto K characters
        for i in range(K):
            T += S[i]
 
        T = list(T)
        # iterating in reverse direction
        for i in range(K - 1, -1, -1):
 
            # find the current character in the set
            if(T[i] in found):
                it = T[i]
 
            # increment the iterator
            it = chr(ord(it)+1)
 
            # check if some bigger character exists in set
            if (it in found):
                break
 
        # Replace current character with that found in set
        T[i] = it
 
        # Replace all characters after with minChar
        for j in range(i + 1, K):
            T[j] = minChar
 
    return T
 
# Driver Code to test the above function
if __name__ == "__main__":
 
    S = "abc"
    N = len(S)
 
    # Length of required string
    K = 3
 
    T = findString(S, N, K)
    print("Lexicographically Smallest String "
          "greater than " + S + " is " + "".join(T))
 
    # This code s contributed by ukasp.


C#




/* C# Program to find the lexicographically
smallest string T greater than S whose
letters are subset of letters of S */
using System;
using System.Collections.Generic;
 
public class LexicographicallySmallest {
  // function to find the lexicographically
  // smallest string greater than S
  public static string FindString(string S, int N, int K) {
    // stores minimum character
    char minChar = 'z';
    // stores unique characters of
    // string in sorted order
    HashSet < char > found = new HashSet < char > ();
 
    // Loop through to find the minimum character
    // and stores characters in the set
    for (int i = 0; i < N; i++) {
      found.Add(S[i]);
      if (S[i] < minChar) {
        minChar = S[i];
      }
    }
 
    string T = "";
 
    // Case 1: If N < K
    if (N < K) {
      // copy the string S upto N characters
      T += S;
 
      // append minChar to make the remaining
      // characters
      for (int i = 0; i < K - N; i++) {
        T += minChar;
      }
    }
 
    // Case 2 : If N >= K
    else {
      T = "";
 
      // copy the string S upto K characters
      for (int i = 0; i < K; i++) {
        T += S[i];
      }
 
      // iterating in reverse direction
      int j;
      for (j = K - 1; j >= 0; j--) {
        // find the current character in the set
        if (found.Contains(T[j])) {
          char it = T[j];
          // increment the iterator
          it = (char)(it + 1);
          // check if some bigger character exists in set
          if (found.Contains(it)) {
            break;
          }
        }
      }
 
      // Replace current character with that found in set
      char[] charArray = T.ToCharArray();
      charArray[j] = (char)(charArray[j] + 1);
      T = new string(charArray);
 
      // Replace all characters after with minChar
      for (int k = j + 1; k < K; k++) {
        charArray[k] = minChar;
      }
      T = new string(charArray);
    }
 
    return T;
  }
 
  // Driver Code to test the above function
  public static void Main(string[] args) {
    string S = "abc";
    int N = S.Length;
 
    // Length of required string
    int K = 3;
 
    string T = FindString(S, N, K);
    Console.WriteLine("Lexicographically Smallest String greater than " +
      S + " is " + T);
  }
}
 
// Contributed by adityasharmadev01


Javascript




// function to find the lexicographically
// smallest string greater than S
 
function findString(S, N, K) {
  // stores minimum character
  let minChar = "z";
 
  // stores unique characters of
  // string in sorted order
  let found = new Set();
 
  // Loop through to find the minimum character
  // and stores characters in the set
  for (let i = 0; i < N; i++) {
    found.add(S[i]);
    if (S[i] < minChar) {
      minChar = S[i];
    }
  }
 
  let T = "";
 
  // Case 1: If N < K
  if (N < K) {
    // copy the string S upto N characters
    T = S;
 
    // append minChar to make the remaining
    // characters
    for (let i = 0; i < K - N; i++) {
      T += minChar;
    }
  }
 
  // Case 2 : If N >= K
  else {
    T = "";
 
    // copy the string S upto K characters
    for (let i = 0; i < K; i++) {
      T += S[i];
    }
 
    T = T.split("");
    // iterating in reverse direction
    let i;
    for (i = K - 1; i >= 0; i--) {
      // find the current character in the set
      if (found.has(T[i])) {
        var it = T[i];
      }
 
      // increment the iterator
      it = String.fromCharCode(it.charCodeAt(0) + 1);
 
      // check if some bigger character exists in set
      if (found.has(it)) {
        break;
      }
    }
 
    // Replace current character with that found in set
    T[i] = it;
 
    // Replace all characters after with minChar
    for (let j = i + 1; j < K; j++) {
      T[j] = minChar;
    }
  }
 
  return T.join("");
}
 
// Driver Code to test the above function
let S = "abc";
let N = S.length;
 
// Length of required string
let K = 3;
 
let T = findString(S, N, K);
console.log(
  "Lexicographically Smallest String greater than " + S + " is " + T
);
 
// This code is contributed by codebraxnzt


Output: 

Lexicographically Smallest String greater than abc is aca

 

Time Complexity: O(N + K), where N is the length of given string and K is the length of required string.
Space Complexity : O(K) 
 



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads