316. Remove Duplicate Letters


  • 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"

Method 1

【O(n) time | O(n) space】
package Leetcode.Stack;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * @Author zhengxingxing
 * @Date 2025/06/22
 */
public class RemoveDuplicateLetters {

    public static String removeDuplicateLetters(String s) {
        int[] count = new int[26]; // Array to count the remaining occurrences of each character.
        boolean[] inStack = new boolean[26]; // Flags to indicate if a character is already in the stack.

        // First pass: count the occurrences of each character in the string.
        for (char c : s.toCharArray()) {
            count[c - 'a']++;
        }

        Deque<Character> stack = new ArrayDeque<>(); // Monotonic stack to build the result.

        // Iterate through each character in the string.
        for (char c : s.toCharArray()) {
            count[c - 'a']--; // Decrement the count for this character, as it's now being processed.

            // If the character is already in the stack, skip it to avoid duplicates.
            if (inStack[c - 'a']) {
                continue;
            }

            /**
             * While the stack is not empty, and the current character is lexicographically
             * smaller than the character at the top of the stack, and the character at the
             * top of the stack will appear again later (count > 0):
             *   - Pop the top character from the stack.
             *   - Mark it as not in the stack.
             * This ensures that:
             *   1. The result remains lexicographically smallest by removing bigger letters
             *      that can still be placed later.
             *   2. Each letter appears only once in the result.
             */
            while (!stack.isEmpty()
                    && c < stack.peekLast()
                    && count[stack.peekLast() - 'a'] > 0) {
                char removed = stack.removeLast(); // Remove the top character from the stack.
                inStack[removed - 'a'] = false;    // Mark the removed character as not in the stack.
            }

            // Add the current character to the stack and mark it as present.
            stack.addLast(c);
            inStack[c - 'a'] = true;
        }

        // Build the final result string from the characters in the stack.
        StringBuilder sb = new StringBuilder();
        for (char c : stack) {
            sb.append(c);
        }
        return sb.toString();
    }
    
    public static void main(String[] args) {
        System.out.println(removeDuplicateLetters("bcabc"));      // Output: "abc"
        System.out.println(removeDuplicateLetters("cbacdcbc"));   // Output: "acdb"
    }
}




Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • 1081. Smallest Subsequence of Distinct Characters
  • 1673. Find the Most Competitive Subsequence
  • 2138. Divide a String Into Groups of Size k
  • 3085. Minimum Deletions to Make String K-Special
  • 3443. Maximum Manhattan Distance After K Changes