Lexicographically smallest string formed by removing duplicates using stack
Last Updated :
13 Feb, 2023
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));
}
}
Time Complexity: O(N)
Auxiliary Space: O(N)
Related Articles:
Similar Reads
Lexicographically smallest string formed by removing duplicates 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: xyzExplanation: Removing the duplicate characters at indices 0 and 1 in the given str
7 min read
Lexicographically smallest string formed by removing at most one character Given a string s, the task is to find the lexicographically smallest string that can be formed by removing at most one character from the given string. Examples: Input: s = "abcda" Output: "abca"Explanation: One can remove 'd' to get "abca" which is the lexicographically smallest string possible. In
4 min read
Lexicographically smallest String by removing exactly K characters Given a string s consisting of only lowercase characters, the task is to find the lexicographically smallest string after removing exactly k characters from the string. But you have to modify the value of k, i.e., if the length of the string is a power of 2, reduce k by half, else multiply k by 2. Y
15 min read
Lexicographically smallest subsequence possible by removing a character from given string Given a string S of length N, the task is to find the lexicographically smallest subsequence of length (N - 1), i.e. by removing a single character from the given string. Examples: Input: S = "geeksforgeeks"Output: "eeksforgeeks"Explanation: Lexicographically smallest subsequence possible is "eeksfo
8 min read
Lexicographically smallest String formed by extracting single character Given a string array S, the task is to find the lexicographically smallest string that can be formed by extracting a single character in each string from the string array S. Example: Input: S = ["xy", "fd"]Output: "dx"Explanation: The possible strings formed by extracting a single character from eac
5 min read
Kth lexicographically smallest distinct String from given Array of Strings Given an array arr having N strings and an integer K, the task is to find the lexicographically smallest Kth distinct string. Print an empty string if no such string exists. Example: Input: arr[]={"aa", "aa", "bb", "cc", "dd", "cc"}, K = 2Output: ddExplanation: Distinct strings are: "bb", "dd". 2nd
4 min read