Skip to content
Related Articles
Get the best out of our app
GeeksforGeeks App
Open App
geeksforgeeks
Browser
Continue

Related Articles

Lexicographically smallest string formed by removing duplicates using stack

Improve Article
Save Article
Like Article
Improve Article
Save Article
Like Article

Given a string S consisting of lowercase alphabets, the task is to find the lexicographically smallest string that can be obtained by removing duplicates from the given string S.

Examples:

Input: S = “yzxyz”
Output: xyz
Explanation: Removing the duplicate characters at indices 0 and 1 in the given string, the remaining string “xyz” consists only of unique alphabets only and is the smallest possible string in lexicographical order.

Input: S = “acbc”
Output: “abc”
Explanation: Removing the duplicate characters at index 3 in the given string, the remaining string “abc” consists only of unique alphabets only and is the smallest possible string in lexicographical order.

Approach: Follow the steps below to solve the problem:

  • Initialize a stack st to store the Lexicographically smallest string, and a visited array vis to find the duplicate letters and map to store the last index of any character.
  • Traverse the string and find the last index of every unique character present in the string and store it in the map.
  • Traverse the string and if the current character is not seen before, While (stack is not empty and current character < character present at top of the stack and last_index[st.top()]>i)
    • then set st.top=0 in vis and pop it from the stack.
  • Initialize an empty string, res.
  • While the stack is not empty add st.top() in the res then pop it from the stack.
  • At last, reverse the string and return it.

Below is the implementation of the above approach:

C++




// C++ program for the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to remove Duplicate Letters
// from string s such that it gives
// Lexicographically smallest string
 
string removeDuplicateLetters(string s)
{
    // Stack to store Lexicographically
    // smallest string
    stack<char> st;
 
    // Visited array to find the
    // duplicate letters
    vector<int> vis(26, 0);
 
    // Map to store the last index
    // of any character
    unordered_map<char, int> last_index;
 
    // Size of string S
    int n = s.size();
 
    // Find last index of every unique
    // character  present in the string
    for (int i = 0; i < n; i++) {
        last_index[s[i]] = i;
    }
 
    // Traverse the string
    for (int i = 0; i < s.length(); i++) {
 
        // Current character
        char curr = s[i];
 
        // If curr is not seen before
        if (!vis[curr - 'a']) {
 
            // While the stack is not empty
            // and current character <
            // character present at top of
            // stack and last_index[st.top()]>i
            while (!st.empty() && curr < st.top()
                   && last_index[st.top()] > i) {
 
                // Set st.top() = 0 in vis
                vis[st.top() - 'a'] = 0;
 
                // Pop it from stack
                st.pop();
            }
 
            // Push curr in stack
            st.push(curr);
 
            // Set Curr-'a' = 1 in vis
            vis[curr - 'a'] = 1;
        }
    }
 
    // Initialize a empty string
    string res = "";
 
    // While stack is not empty
    while (!st.empty()) {
        res += st.top();
        st.pop();
    }
 
    // Reverse the string
    reverse(res.begin(), res.end());
 
    // return the string
    return res;
}
 
// Driver Code
int main()
{
 
    string S = "yzxyz";
    cout << removeDuplicateLetters(S) << endl;
    S = "acbc";
    cout << removeDuplicateLetters(S) << endl;
 
    return 0;
}

Java




// Java program for the above approach
 
import java.io.*;
import java.util.*;
 
class GFG {
 
    // Function to remove Duplicate Letters
    // from string s such that it gives
    // Lexicographically smallest string
    static String removeDuplicateLetters(String s)
    {
        // Stack to store Lexicographically
        // smallest string
        Stack<Character> st = new Stack<>();
        // Visited array to find the
        // duplicate letters
        int[] vis = new int[26];
 
        // Map to store the last index
        // of any character
        Map<Character, Integer> lastIndex = new HashMap<>();
 
        // Size of string S
        int n = s.length();
 
        // Find last index of every unique
        // character  present in the string
        for (int i = 0; i < n; i++) {
            lastIndex.put(s.charAt(i), i);
        }
 
        // Traverse the string
        for (int i = 0; i < s.length(); i++) {
 
            // Current character
            char curr = s.charAt(i);
 
            // If curr is not seen before
            if (vis[curr - 'a'] == 0) {
 
                // While the stack is not empty
                // and current character <
                // character present at top of
                // stack and last_index[st.top()]>i
                while (!st.isEmpty() && curr < st.peek()
                       && lastIndex.get(st.peek()) > i) {
                    // Set st.top() = 0 in vis
                    vis[st.peek() - 'a'] = 0;
 
                    // Pop it from stack
                    st.pop();
                }
                // Push curr in stack
                st.push(curr);
                // Set Curr-'a' = 1 in vis
                vis[curr - 'a'] = 1;
            }
        }
 
        // Initialize a empty string
        StringBuilder res = new StringBuilder();
        // While stack is not empty
        while (!st.isEmpty()) {
            res.append(st.pop());
        }
 
        // Reverse & return the string
        return res.reverse().toString();
    }
 
    public static void main(String[] args)
    {
        String S = "yzxyz";
        System.out.println(removeDuplicateLetters(S));
        S = "acbc";
        System.out.println(removeDuplicateLetters(S));
    }
}
 
// This code is contributed by lokesh.

Python3




# C++ program for the above approach
 
# Function to remove Duplicate Letters
# from string s such that it gives
# Lexicographically smallest string
 
 
def removeDuplicateLetters(s):
 
    # Stack to store Lexicographically
    # smallest string
    st = []
 
    # Visited array to find the
    # duplicate letters
    vis = [0 for _ in range(26)]
 
    # Map to store the last index
    # of any character
    last_index = {}
 
    # Size of string S
    n = len(s)
 
    # Find last index of every unique
    # character  present in the string
    for i in range(0, n):
        last_index[s[i]] = i
 
    # Traverse the string
    for i in range(0, len(s)):
 
        # Current character
        curr = s[i]
 
    # If curr is not seen before
        if (not vis[ord(curr) - ord('a')]):
 
            # While the stack is not empty
            # and current character <
            # character present at top of
            # stack and last_index[st.top()]>i
            while (len(st) != 0 and curr < st[-1]
                   and last_index[st[-1]] > i):
 
                # Set st.top() = 0 in vis
                vis[ord(st[-1]) - ord('a')] = 0
 
        # Pop it from stack
                st.pop()
 
    # Push curr in stack
            st.append(curr)
 
    # Set Curr-'a' = 1 in vis
            vis[ord(curr) - ord('a')] = 1
 
    # Initialize a empty string
    res = ""
 
    # While stack is not empty
    while (len(st) != 0):
        res += st[-1]
        st.pop()
 
    # Reverse the string
    res = res[::-1]
 
    # return the string
    return res
 
 
# Driver Code
if __name__ == "__main__":
    S = "yzxyz"
    print(removeDuplicateLetters(S))
    S = "acbc"
    print(removeDuplicateLetters(S))
 
    # This code is contributed by rakeshsahni

Javascript




// JavaScript program for the above approach
 
function removeDuplicateLetters(s) {
    // Stack to store Lexicographically
    // smallest string
    let st = [];
 
    // Visited array to find the
    // duplicate letters
    let vis = new Array(26).fill(0);
 
    // Map to store the last index
    // of any character
    let last_index = new Map();
 
    // Size of string S
    let n = s.length;
 
    // Find last index of every unique
    // character  present in the string
    for (let i = 0; i < n; i++) {
        last_index.set(s[i], i);
    }
 
    // Traverse the string
    for (let i = 0; i < n; i++) {
 
        // Current character
        let curr = s[i];
 
        // If curr is not seen before
        if (!vis[curr.charCodeAt(0) - 'a'.charCodeAt(0)]) {
 
            // While the stack is not empty
            // and current character <
            // character present at top of
            // stack and last_index[st.top()]>i
            while (st.length !== 0 && curr < st[st.length - 1]
                && last_index.get(st[st.length - 1]) > i) {
 
                // Set st.top() = 0 in vis
                vis[st[st.length - 1].charCodeAt(0) - 'a'.charCodeAt(0)] = 0;
 
                // Pop it from stack
                st.pop();
            }
 
            // Push curr in stack
            st.push(curr);
 
            // Set Curr-'a' = 1 in vis
            vis[curr.charCodeAt(0) - 'a'.charCodeAt(0)] = 1;
        }
    }
 
    // Initialize a empty string
    let res = "";
 
    // While stack is not empty
    while (st.length !== 0) {
        res += st.pop();
    }
 
    // Reverse the string
    res = res.split("").reverse().join("");
 
    // return the string
    return res;
}
 
// Driver Code
console.log(removeDuplicateLetters("yzxyz"));
console.log(removeDuplicateLetters("acbc"));

C#




using System;
using System.Collections.Generic;
 
class Program {
    // Function to remove Duplicate Letters
    // from string s such that it gives
    // Lexicographically smallest string
    static string RemoveDuplicateLetters(string s)
    {
        // Stack to store Lexicographically
        // smallest string
        Stack<char> st = new Stack<char>();
        // Visited array to find the
        // duplicate letters
        int[] vis = new int[26];
        // Map to store the last index
        // of any character
        Dictionary<char, int> last_index
            = new Dictionary<char, int>();
        // Size of string S
        int n = s.Length;
 
        // Find last index of every unique
        // character  present in the string
        for (int i = 0; i < n; i++) {
            last_index[s[i]] = i;
        }
        // Traverse the string
        for (int i = 0; i < s.Length; i++) {
            // Current character
            char curr = s[i];
 
            // If curr is not seen before
            if (vis[curr - 'a'] == 0) {
                // While the stack is not empty
                // and current character <
                // character present at top of
                // stack and last_index[st.top()]>i
                while (st.Count != 0 && curr < st.Peek()
                       && last_index[st.Peek()] > i) {
                    // Set st.top() = 0 in vis
                    vis[st.Peek() - 'a'] = 0;
                    // Pop it from stack
                    st.Pop();
                }
                // Push curr in stack
                st.Push(curr);
                // Set Curr-'a' = 1 in vis
                vis[curr - 'a'] = 1;
            }
        }
 
        // Initialize a empty string
        string res = "";
        // While stack is not empty
        while (st.Count != 0) {
            res += st.Peek();
            st.Pop();
        }
 
        char[] arr = res.ToCharArray();
        // Reverse the string
        Array.Reverse(arr);
        res = new string(arr);
 
        // return the string
        return res;
    }
 
    // Driver Code
    static void Main(string[] args)
    {
        string S = "yzxyz";
        Console.WriteLine(RemoveDuplicateLetters(S));
        S = "acbc";
        Console.WriteLine(RemoveDuplicateLetters(S));
    }
}

Output

xyz
abc

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

Related Articles:


My Personal Notes arrow_drop_up
Last Updated : 13 Feb, 2023
Like Article
Save Article
Similar Reads
Related Tutorials