Skip to main content

Remove Duplicate Letters - Solution & Explanation

MediumStringStackGreedyMonotonic Stack17 min readAsked at: Amazon, Microsoft, Meta +10
Practice this problem

Problem Statement

Given a string s, remove duplicate letters so that every letter appears once and only once. You must make sure your result is the smallest in lexicographical order among all possible results.

 

Example 1:

Input: s = "bcabc"
Output: "abc"

Example 2:

Input: s = "cbacdcbc"
Output: "acdb"

 

Constraints:

  • 1 <= s.length <= 104
  • s consists of lowercase English letters.

 

Note: This question is the same as 1081: https://leetcode.com/problems/smallest-subsequence-of-distinct-characters/

Approach Overview

Problem Overview: Given a string s, remove duplicate characters so every letter appears exactly once while keeping the result as the smallest possible lexicographical string. The relative ordering constraints of the original string still matter, so you cannot freely reorder characters.

Approach 1: Greedy and Stack (O(n) time, O(1) space)

This approach uses a stack to build the result while maintaining lexicographical order. First record the last occurrence index of every character. Then iterate through the string and maintain a visited set. For each character, pop elements from the stack while the current character is smaller than the stack top and the stack top appears later in the string. This greedy decision ensures the final string remains lexicographically minimal. The stack effectively becomes a monotonic stack that enforces increasing order when possible.

Approach 2: Iterative Result String Construction (O(n) time, O(1) space)

This method builds the answer string directly instead of using an explicit stack structure. Iterate through characters and maintain a result string along with a visited map. When a new character arrives, repeatedly remove the last character from the result if it is lexicographically larger and appears again later in the string. Then append the current character and mark it as used. This follows the same greedy principle as the stack approach but uses string operations instead of a dedicated stack data structure. The algorithm still scans the input once and uses constant extra memory for character tracking.

Recommended for interviews: The greedy stack solution is the expected answer. Interviewers want to see that you track the last occurrence of each character and maintain a lexicographically minimal structure while iterating once through the string. Understanding how the greedy decision interacts with stack popping demonstrates strong algorithmic reasoning. The iterative string version shows the same logic but the explicit stack version is easier to explain during interviews.

Approach 1: Approach 1: Greedy and Stack

This approach uses a stack to build the resultant string such that it is the smallest lexicographical order. We will also use an array to keep count of each character’s frequency and a boolean array to track the characters that have been added to the stack. As we iterate over each character, we decide whether to add it to the stack or skip it based on the frequency and lexicographical conditions.

The code iterates through the string, keeping track of character frequencies and deciding whether to add each character to a stack based on lexicographical ordering and frequency constraints. Characters are popped from the stack if they have occurred later, are greater than the current character, and are not the last occurrence.

Code

C

C++

Java

Python

C#

JavaScript

Complexity

Time Complexity: O(n), where n is the length of the string, as each character is pushed and popped from the stack at most once.
Space Complexity: O(1), because the stack contains at most 26 characters, and other auxiliary data structures are of constant size.

Try this approach in the editor →

Approach 2: Approach 2: Iterative with Result String Construction

This approach focuses on iteratively constructing the result string while ensuring that the result remains lexicographically smallest by checking each character and including it in the result only if it meets certain frequency and order criteria.

In this solution, a character set is updated via a general loop to progressively add elements to the result string. This method leverages frequency checks of character availability while ensuring characters are not redundant in the result.

Code

C

C++

Java

Python

C#

JavaScript

Complexity

Time Complexity: O(n), where n is the length of the input string.
Space Complexity: O(1), considering character storage is bounded to a maximum of 26.

Try this approach in the editor →

Approach 3: Stack

We use an array last to record the last occurrence of each character, a stack to save the result string, and an array vis or an integer variable mask to record whether the current character is in the stack.

Traverse the string s, for each character c, if c is not in the stack, we need to check whether the top element of the stack is greater than c. If it is greater than c and the top element of the stack will appear later, we pop the top element of the stack and push c into the stack.

Finally, concatenate the elements in the stack into a string and return it as the result.

The time complexity is O(n), and the space complexity is O(n). Where n is the length of the string s.

Code

Python

Java

C++

Go

Try this approach in the editor →

Approach 4: Default Approach

Code

Python

Go

Try this approach in the editor →

Complexity Comparison

ApproachComplexity
Approach 1: Greedy and Stack

Time Complexity: O(n), where n is the length of the string, as each character is pushed and popped from the stack at most once.
Space Complexity: O(1), because the stack contains at most 26 characters, and other auxiliary data structures are of constant size.

Approach 2: Iterative with Result String Construction

Time Complexity: O(n), where n is the length of the input string.
Space Complexity: O(1), considering character storage is bounded to a maximum of 26.

Stack—
Default Approach—

Detailed Complexity Analysis

ApproachTimeSpaceWhen to Use
Greedy + Monotonic StackO(n)O(1)Best general solution. Clear logic for maintaining smallest lexicographic order while ensuring each character appears once.
Iterative Result String ConstructionO(n)O(1)Useful when implementing without an explicit stack structure while applying the same greedy removal logic.

Video Solution

Remove Duplicate Letters | Leetcode #316 • Techdose • 37,770 views views

Watch 9 more video solutions →

Frequently Asked Questions

Is Remove Duplicate Letters easy or hard?
Remove Duplicate Letters is typically classified as a medium-level problem. The implementation is not long, but identifying the greedy rule and safely popping characters from a stack requires careful reasoning about future occurrences in the string.
Remove Duplicate Letters Python/Java solution
In Python or Java, implement the greedy stack approach using a list or stack structure along with arrays to track last occurrences and visited characters. Iterate through the string once, pop larger characters that appear later, and append the current character if it hasn't been used yet.
How to solve Remove Duplicate Letters in O(n)?
Record the last index of each character in the string. Iterate through the string and maintain a stack and a visited set. While the stack is not empty and the current character is smaller than the top of the stack and the top appears later again, pop it from the stack. Push the current character if it hasn't been used. This guarantees the lexicographically smallest valid string.
What is the best approach for Remove Duplicate Letters?
The greedy monotonic stack approach is the most efficient solution. Track the last occurrence of each character and iterate through the string once. Maintain a stack and remove larger characters that will appear again later, ensuring the resulting string stays lexicographically smallest. This runs in O(n) time with O(1) extra space.
Is Remove Duplicate Letters asked at Google/Amazon/Meta?
Remove Duplicate Letters frequently appears in interviews at companies like Amazon, Google, and Meta because it tests greedy reasoning and stack usage. Candidates must combine character frequency tracking with a monotonic structure, which is a common pattern in advanced string problems.
What data structure is used in Remove Duplicate Letters?
A stack is the primary data structure used in the optimal solution. The stack maintains the current lexicographically smallest sequence while allowing removal of previously added characters. A hash map or array tracks the last occurrence of each character, and a boolean array or set tracks visited characters.
What is the time complexity of Remove Duplicate Letters?
The optimal solution runs in O(n) time where n is the length of the string. Each character is pushed to and popped from the stack at most once, so the total number of operations is linear. Space complexity is O(1) because the alphabet size is fixed (26 lowercase letters).

Ready to solve this problem?

Practice Remove Duplicate Letters with our built-in code editor and test cases.

Practice on FleetCode