Open In App

Lexicographically smallest string formed by removing duplicates using stack

Last Updated : 13 Feb, 2023
Comments
Improve
Suggest changes
Like Article
Like
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:


Next Article
Practice Tags :

Similar Reads