Code Logo

Remove Duplicate Letters

Published at23 Jul 2026
Hard 0 views
Like0

Given a string of lowercase letters, remove duplicate letters so each appears exactly once. The result must be the smallest lexicographical result possible while preserving the relative order of first occurrences of each letter.

A monotonic increasing stack with a frequency counter solves this. Count frequencies. Iterate, decrement count for each char. If already used, skip. While the stack top is greater than the current char and the top char appears later, pop the top (mark as unused). Push current char, mark as used. This greedy approach ensures the smallest lexicographical result.

Example Input & Output

Example 1
Input
abcd
Output
abcd
Explanation

No duplicates.

Example 2
Input
bcabc
Output
abc
Explanation

Smallest lexicographical.

Example 3
Input
cbacdcbc
Output
acdb
Explanation

Lexicographically smallest.

Algorithm Flow

Recommendation Algorithm Flow for Remove Duplicate Letters
Recommendation Algorithm Flow for Remove Duplicate Letters

Solution Approach

Count frequencies. Iterate, decrement. Skip if used. While stack top > char and top appears later, pop. Push char.

function solution(s) {
  var cnt = {};
  for (var i = 0; i < s.length; i++) cnt[s[i]] = (cnt[s[i]]||0) + 1;
  var stack = [], used = {};
  for (var i = 0; i < s.length; i++) {
    var ch = s[i];
    cnt[ch]--;
    if (used[ch]) continue;
    while (stack.length && ch < stack[stack.length-1] && cnt[stack[stack.length-1]] > 0)
      used[stack.pop()] = false;
    stack.push(ch);
    used[ch] = true;
  }
  return stack.join("");
}

Time O(n), Space O(n).

Best Answers

java
import java.util.*;
class Solution {
    public String solution(String s) {
        int[] cnt = new int[26];
        boolean[] used = new boolean[26];
        Stack<Character> stack = new Stack<>();
        for (char ch : s.toCharArray()) cnt[ch - 'a']++;
        for (char ch : s.toCharArray()) {
            cnt[ch - 'a']--;
            if (used[ch - 'a']) continue;
            while (!stack.isEmpty() && ch < stack.peek() && cnt[stack.peek() - 'a'] > 0)
                used[stack.pop() - 'a'] = false;
            stack.push(ch);
            used[ch - 'a'] = true;
        }
        StringBuilder sb = new StringBuilder();
        while (!stack.isEmpty()) sb.insert(0, stack.pop());
        return sb.toString();
    }
}