Skip to content
Related Articles

Related Articles

Lexicographically smallest String by moving one Subsequence to the end

View Discussion
Improve Article
Save Article
  • Last Updated : 28 Jul, 2022
View Discussion
Improve Article
Save Article

Given a string S of size N, having lowercase alphabets, the task is to find the lexicographically minimum string after moving a subsequence to the end of the string only once.

Example:

Input: N = 3, S = “asa” 
Output: aas
Explanation: The optimal subsequence is “s”
Removed, and added at last. Hence the final string is ‘aa’ + ‘s’ =’aas’

Input: N = 7, S = “fabccac” 
Output: aacfbcc
Explanation: The optimal subsequence is “fbcc”
Any other subsequence will not give the minimum
Hence the final string is ‘aac’ + ‘fbcc’ = ‘aacfbcc’

 

Approach: The problem can be solved based on the following observation: 

To find the lexicographically minimum string the selected subsequence should follow the pattern.

  • The 1st character of the selected subsequence to be removed should be same or greater than the last character of the retaining subsequence.
  • The non selected subsequence shall form a non-decreasing sequence.

Follow the steps to solve the problem:

  • Initialize a boolean array to maintain the position of characters if included in the subsequence to be shuffled or not.
  • Maintain a stack for finding non-decreasing subsequence of retaining characters
  • At every character, pop all characters greater than the current character from the stack.

Below is the implementation for the above approach:

C++




// C++ code for the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to find lexicographically minimum
string LexMin(int n, string s)
{
    // Boolean array for storing positions
    // and frequencies
    vector<int> last(26, -1);
    for (int i = 0; i < n; i++) {
        last[s[i] - 'a'] = i;
    }
    int dig = 0;
    int mx = 26;
 
    // ans for storing resultant string
    // ans1 for leftout and ans2 for picked up
    string ans = s, ans1, ans2;
    for (int i = 0; i < n; i++) {
 
        // For every i we will find its
        // last occurrence last[dig]
        while (dig < 26 && i > last[dig])
            dig++;
        if (dig == mx) {
            string ans3 = ans2, ans4;
            for (int j = i; j < n; j++) {
 
                // Adding the character
                if (s[j] == ('a' + mx)) {
                    ans4.push_back(s[j]);
                }
                else {
                    ans3.push_back(s[j]);
                }
            }
 
            // Remove the other half and
            // store the substring upto i
            ans2 += s.substr(i);
 
            // Find out the minimum
            // and put it into ans
            ans = min(ans, ans1
                               + min(ans2, ans4 + ans3));
            break;
        }
        else if (dig > mx) {
            ans = min(ans, ans1
                               + ans2 + s.substr(i));
            break;
        }
 
        // ans1 holds value retaining  values
        if (s[i] == ('a' + dig)) {
            ans1.push_back(s[i]);
        }
        else {
            if (mx == 26)
                mx = (s[i] - 'a');
            ans2.push_back(s[i]);
        }
 
        // Corner cases
        if (i == n - 1)
            ans = min(ans, ans1 + ans2);
    }
 
    // Return the ans
    return ans;
}
 
// Driver code
int main()
{
    int N = 3;
    string s = "asa";
 
    // Function call
    cout << LexMin(N, s) << endl;
    return 0;
}

Python3




# Python3 code for the above approach
 
# Function to find lexicographically minimum
def LexMin(n, s) :
 
    # Boolean array for storing positions
    # and frequencies
    last = [-1] * 26;
    for i in range(n) :
        last[ord(s[i]) - ord('a')] = i;
 
    dig = 0;
    mx = 26;
 
    # ans for storing resultant string
    # ans1 for leftout and ans2 for picked up
    ans = s;
    ans1,ans2 = "","";
    for i in range(n) :
 
        # For every i we will find its
        # last occurrence last[dig]
        while (dig < 26 and i > last[dig]) :
            dig += 1;
        if (dig == mx) :
            ans3 = ans2;
            ans4 = "";
            for j in range(1, n) :
 
                # Adding the character
                if (ord(s[j]) == (ord('a') + mx)) :
                    ans4 += s[j] ;
     
                else :
                    ans3 += s[j];
 
            # Remove the other half and
            # store the substring upto i
            ans2 += s[:i];
 
            # Find out the minimum
            # and put it into ans
            ans = min(ans, ans1 + min(ans2, ans4 + ans3));
            break;
             
        elif (dig > mx) :
            ans = min(ans, ans1 + ans2 + s[:i]);
            break;
 
        # ans1 holds value retaining  values
        if (ord(s[i]) == (ord('a') + dig)) :
            ans1 += s[i];
 
        else :
            if (mx == 26) :
                mx = (ord(s[i]) - ord('a'));
            ans2 += s[i];
 
        # Corner cases
        if (i == n - 1) :
            ans = min(ans, ans1 + ans2);
 
    # Return the ans
    return ans;
 
# Driver code
if __name__ == "__main__" :
 
    N = 3;
    s = "asa";
 
    # Function call
    print(LexMin(N, s));
 
    # This code is contributed by AnkThon

Javascript




<script>
 
// JavaScript code for the above approach
 
 
// Function to find lexicographically minimum
function LexMin(n,s)
{
    // Boolean array for storing positions
    // and frequencies
    let last = new Array(26).fill(-1);
    for (let i = 0; i < n; i++) {
        last[s.charCodeAt(i) - 'a'.charCodeAt(0)] = i;
    }
    let dig = 0;
    let mx = 26;
 
    // ans for storing resultant string
    // ans1 for leftout and ans2 for picked up
    let ans = s, ans1 ="" , ans2 = "";
    for (let i = 0; i < n; i++) {
 
        // For every i we will find its
        // last occurrence last[dig]
        while (dig < 26 && i > last[dig])
            dig++;
        if (dig == mx) {
            let ans3 = ans2, ans4;
            for (let j = 1; j < n; j++) {
 
                // Adding the character
                if (s.charCodeAt(j) == ('a'.charCodeAt(0) + mx)) {
                    ans4 += s[j];
                }
                else {
                    ans3 += s[j];
                }
            }
 
            // Remove the other half and
            // store the substring upto i
            ans2 += s.substring(0,i);
 
            // Find out the minimum
            // and put it into ans
            ans = ans1;
            if(ans2 > ans4 + ans3)
                ans2 = ans4 + ans3;
            if(ans > ans2)
                ans = ans2;
            break;
        }
        else if (dig > mx) {
            if(ans > ans1 + ans2 + s.substring(0,i))
                ans = ans1 + ans2 + s.substring(0,i)
            break;
        }
 
        // ans1 holds value retaining  values
        if (s.charCodeAt(i) == ('a'.charCodeAt(0) + dig)) {
            ans1 += s[i];
        }
        else {
            if (mx == 26)
                mx = (s.charCodeAt(i) - 'a'.charCodeAt(0));
            ans2 += s[i];
        }
 
        // Corner cases
        if (i == n - 1){
            if(ans > ans1 + ans2)
                ans = ans1 + ans2;
        }
    }
 
    // Return the ans
    return ans;
}
 
// Driver code
 
let N = 3;
let s = "asa";
 
// Function call
document.write(LexMin(N, s),"</br>");
 
// This code is contributed by shinjanpatra
 
</script>

Output

aas

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


My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!