Open In App

Lexicographically smallest string formed by removing duplicates using stack

Last Updated : 13 Feb, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

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:



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads