Skip to content
Related Articles

Related Articles

Lexicographically smallest string formed by reversing Substrings of string S exactly K times

View Discussion
Improve Article
Save Article
Like Article
  • Last Updated : 04 Apr, 2022

Given a string S and an integer K, the task is to find the lexicographically smallest string possible after reversing any substring of any length exactly K times. 

Examples:

Input: S = “fgazcbdfge”, K = 3
Output: abcdgfzfge
Explanation: After 1st operation: S = “agfzcbdfge”, in S select S[0 – 2] = “fga” and reverse it
After 2nd operation: S = “abczfgdfge”, in S select S[2 – 4] = “fzc” and reverse it
After 3rd operation: S = “abcdgfzfge”, in S select S[3 – 6] = “zfgd” and reverse it.

Input: S = “abcdefg”, K = 5
Output: abcdefg
Explanation: The string is already lexicographically minimum possible. 
Hence pick any 5 substrings having length 1. So the string will remain unchanged.

 

Approach: To form the lexicographically smallest string in K steps, in each step select an integer L where S[L] is the character before which all characters are in sorted order and an integer R where S[R] is the character which has to be placed at S[L+1] so that all character till S[L+1] will be in sorted order. Reverse the substring S[L..R] in each step and finally, the required string will be obtained. Follow the below steps to solve the problem:

  • Let the given string be S, create another string S1 equal to S then sort S1 in increasing order.
  • This algorithm requires three nested loops, the outer loop will run from 0 to K (number of operations)
  • In every operation, search for two integers L and R, after they have been found we reverse the substring S[L … R] and continue the same for subsequent operations.
  • Using two nested loops search for characters of S1 in S depending upon the number of operations.
  • Since there is the need to only reverse one substring in one operation, just find one character of S1 in S which is S[R] (the character which has to be placed after already sorted characters of S in previous operations) and also find S[L] ( the substring S[0…L-1] is sorted so we don’t have to do anything with it, S[R]will be placed at S[L+1]).
  • After K operations, the lexicographically smallest possible string is obtained.

Illustration: 

In the above illustration, since the first three characters of the original string were in sorted order we dont have to involve them in any operation Search that character which will appear after them in the sorted order, assume it appears at index R (the character will be S[R]) we select the index of character after the first three character as R (the character will be S[R]) Now we reverse the substring S[L…R] which will result in the   character S[R] to appear at S[L+1] and now the first 4 characters ofthe string S are in sorted order    

Below is the implementation of the above approach.

C++




// C++ code to implement the approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to return the lexicographically
// minimum string after k operations
string findStr(string s, int k)
{
    // Sorted string
    string ss = s;
    sort(ss.begin(), ss.end());
 
    // String after each operation
    string ans = "";
 
    for (int i = 0; i < k; i++) {
        ans = "";
        int r = 0;
        int l = -1;
 
        for (int i = 0; i < s.length(); i++) {
            for (int j = 0; j < ss.length(); j++) {
                if (s[j] == ss[i] && i == j) {
                    l = i;
                    break;
                }
                else if (s[j] == ss[i]) {
                    r = j;
                    break;
                }
            }
            if (r > 0)
 
                // to avoid unnecessary checking
                break;
        }
 
        // There is no group of sorted characters
        // in the beginning of the string S
        if (l == -1) {
            for (int i = r; i >= 0; i--)
                ans.push_back(s[i]);
            for (int i = r + 1; i < s.length(); i++)
                ans.push_back(s[i]);
        }
        // string S is already sorted or S = SS
        else if (l == s.length() - 1) {
            ans = s;
        }
        // Some part of string S in the beginning
        // is sorted
        else {
            for (int i = 0; i <= l; i++)
                ans.push_back(s[i]);
            for (int i = r; i > l; i--)
                ans.push_back(s[i]);
            for (int i = r + 1; i < s.length(); i++)
                ans.push_back(s[i]);
        }
        // cout << "after " << i+1 << " operations
        // : " << ans << '\n'; use the above line of
        // code to see how S changes after every
        // operation
 
        s = ans;
    }
    return s;
}
 
// Driver Code
int main()
{
    // Number of operations
    int K = 3;
 
    // Given string
    string S = "fgazcbdfge";
 
    // Final answer string
    string ans = findStr(S, K);
    cout << ans;
    return 0;
}

Java




// Java code to implement the approach
import java.util.*;
 
class GFG {
 
    // Function to return the lexicographically
    // minimum string after k operations
    static String findStr(String s, int k)
    {
 
        // Sorted string
        String ss = s;
        char[] arr = ss.toCharArray();
        Arrays.sort(arr);
 
        ss = new String(arr);
 
        // String after each operation
        String ans = "";
 
        for (int a = 0; a < k; a++) {
            ans = "";
            int r = 0;
            int l = -1;
 
            for (int i = 0; i < s.length(); i++) {
                for (int j = 0; j < ss.length(); j++) {
                    if (s.charAt(j) == ss.charAt(i)
                        && i == j) {
                        l = i;
                        break;
                    }
                    else if (s.charAt(j) == ss.charAt(i)) {
                        r = j;
                        break;
                    }
                }
                if (r > 0)
 
                    // to avoid unnecessary checking
                    break;
            }
 
            // There is no group of sorted characters
            // in the beginning of the string S
            if (l == -1) {
                for (int i = r; i >= 0; i--)
                    ans += s.charAt(i);
                for (int i = r + 1; i < s.length(); i++)
                    ans += s.charAt(i);
            }
            // string S is already sorted or S = SS
            else if (l == s.length() - 1) {
                ans = s;
            }
            // Some part of string S in the beginning
            // is sorted
            else {
                for (int i = 0; i <= l; i++)
                    ans += s.charAt(i);
                for (int i = r; i > l; i--)
                    ans += s.charAt(i);
                for (int i = r + 1; i < s.length(); i++)
                    ans += s.charAt(i);
            }
            // cout << "after " << i+1 << " operations
            // : " << ans << '\n'; use the above line of
            // code to see how S changes after every
            // operation
 
            s = ans;
        }
        return s;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
 
        // Number of operations
        int K = 3;
 
        // Given string
        String S = "fgazcbdfge";
 
        // Final answer string
        String ans = findStr(S, K);
        System.out.print(ans);
    }
}
 
// This code is contributed by ukasp.

Python3




# python3 code to implement the approach
 
# Function to return the lexicographically
# minimum string after k operations
def findStr(s, k):
 
    # Sorted string
    ss = list(s)
    ss.sort()
 
    # String after each operation
    ans = ""
 
    for i in range(0, k):
        ans = ""
        r = 0
        l = -1
 
        for i in range(0, len(s)):
            for j in range(0, len(ss)):
                if (s[j] == ss[i] and i == j):
                    l = i
                    break
 
                elif (s[j] == ss[i]):
                    r = j
                    break
 
            if (r > 0):
 
                # to avoid unnecessary checking
                break
 
        # There is no group of sorted characters
        # in the beginning of the string S
        if (l == -1):
            for i in range(r, -1, -1):
                ans += s[i]
            for i in range(r+1, len(s)):
                ans += s[i]
 
        # string S is already sorted or S = SS
        elif (l == len(s) - 1):
            ans = s
 
        # Some part of string S in the beginning
        # is sorted
        else:
            for i in range(0, l+1):
                ans += s[i]
            for i in range(r, l, -1):
                ans += s[i]
            for i in range(r + 1, len(s)):
                ans += s[i]
 
        # print(f"after {i+1} operations: {ans}")
        # use the above line of
        # code to see how S changes after every
        # operation
 
        s = ans
 
    return s
 
# Driver Code
if __name__ == "__main__":
 
    # Number of operations
    K = 3
 
    # Given string
    S = "fgazcbdfge"
 
    # Final answer string
    ans = findStr(S, K)
    print(ans)
 
# This code is contributed by rakeshsahni

C#




// C# code to implement the approach
using System;
class GFG {
 
  // Function to return the lexicographically
  // minimum string after k operations
  static string findStr(string s, int k)
  {
 
    // Sorted string
    string ss = s;
    char[] arr = ss.ToCharArray();
    Array.Sort(arr);
 
    ss = new string(arr);
 
    // String after each operation
    string ans = "";
 
    for (int a = 0; a < k; a++) {
      ans = "";
      int r = 0;
      int l = -1;
 
      for (int i = 0; i < s.Length; i++) {
        for (int j = 0; j < ss.Length; j++) {
          if (s[j] == ss[i] && i == j) {
            l = i;
            break;
          }
          else if (s[j] == ss[i]) {
            r = j;
            break;
          }
        }
        if (r > 0)
 
          // to avoid unnecessary checking
          break;
      }
 
      // There is no group of sorted characters
      // in the beginning of the string S
      if (l == -1) {
        for (int i = r; i >= 0; i--)
          ans += s[i];
        for (int i = r + 1; i < s.Length; i++)
          ans += s[i];
      }
      // string S is already sorted or S = SS
      else if (l == s.Length - 1) {
        ans = s;
      }
      // Some part of string S in the beginning
      // is sorted
      else {
        for (int i = 0; i <= l; i++)
          ans += s[i];
        for (int i = r; i > l; i--)
          ans += s[i];
        for (int i = r + 1; i < s.Length; i++)
          ans += s[i];
      }
      // cout << "after " << i+1 << " operations
      // : " << ans << '\n'; use the above line of
      // code to see how S changes after every
      // operation
 
      s = ans;
    }
    return s;
  }
 
  // Driver Code
  public static void Main()
  {
 
    // Number of operations
    int K = 3;
 
    // Given string
    string S = "fgazcbdfge";
 
    // Final answer string
    string ans = findStr(S, K);
    Console.Write(ans);
  }
}
 
// This code is contributed by Samim Hossain Mondal.

Javascript




<script>
       // JavaScript code for the above approach
 
       // Function to return the lexicographically
       // minimum string after k operations
       function findStr(s, k)
       {
        
           // Sorted string
           let ss = s.split('');
           ss.sort(function (a, b) { return a.charCodeAt(0) - b.charCodeAt(0) })
 
           // String after each operation
           let ans = [];
 
           for (let i = 0; i < k; i++) {
               ans = [];
               let r = 0;
               let l = -1;
 
               for (let i = 0; i < s.length; i++)
               {
                   for (let j = 0; j < ss.length; j++)
                   {
                       if (s[j] == ss[i] && i == j)
                       {
                           l = i;
                           break;
                       }
                       else if (s[j] == ss[i]) {
                           r = j;
                           break;
                       }
                   }
                   if (r > 0)
 
                       // to avoid unnecessary checking
                       break;
               }
 
               // There is no group of sorted characters
               // in the beginning of the string S
               if (l == -1) {
                   for (let i = r; i >= 0; i--)
                       ans.push(s[i]);
                   for (let i = r + 1; i < s.length; i++)
                       ans.push(s[i]);
               }
                
               // string S is already sorted or S = SS
               else if (l == s.length - 1) {
                   ans = s;
               }
                
               // Some part of string S in the beginning
               // is sorted
               else {
                   for (let i = 0; i <= l; i++)
                       ans.push(s[i]);
                   for (let i = r; i > l; i--)
                       ans.push(s[i]);
                   for (let i = r + 1; i < s.length; i++)
                       ans.push(s[i]);
               }
 
               // code to see how S changes after every
               // operation
 
               s = [...ans];
           }
           return s.join('');
       }
 
       // Driver Code
       // Number of operations
       let K = 3;
 
       // Given string
       let S = "fgazcbdfge";
 
       // Final answer string
       let ans = findStr(S, K);
       document.write(ans);
 
    // This code is contributed by Potta Lokesh
   </script>

 
 

Output

abcdgfzfge

 

Time Complexity: O(K * N2) where N  is the length of the string 
Auxiliary Space: O(1)

 


My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!