Smallest Subsequence of Distinct Characters

medium monotonic stack greedy string

Problem

Given a string s, return the lexicographically smallest subsequence of s that contains all the distinct characters of s exactly once.

Inputs = "bcabc"
Output"abc"
The distinct characters are a, b, c. Among all subsequences using each once ("bca", "bac", "cab", "abc"), "abc" is lexicographically smallest.

def smallest_subsequence(s):
    last = {c: i for i, c in enumerate(s)}
    stack = []
    seen = set()
    for i, c in enumerate(s):
        if c in seen:
            continue
        while stack and stack[-1] > c and last[stack[-1]] > i:
            seen.discard(stack.pop())
        stack.append(c)
        seen.add(c)
    return "".join(stack)
function smallestSubsequence(s) {
  const last = {};
  for (let i = 0; i < s.length; i++) last[s[i]] = i;
  const stack = [];
  const seen = new Set();
  for (let i = 0; i < s.length; i++) {
    const c = s[i];
    if (seen.has(c)) continue;
    while (stack.length && stack[stack.length - 1] > c && last[stack[stack.length - 1]] > i) {
      seen.delete(stack.pop());
    }
    stack.push(c);
    seen.add(c);
  }
  return stack.join("");
}
class Solution {
    public String smallestSubsequence(String s) {
        int[] last = new int[26];
        for (int i = 0; i < s.length(); i++) last[s.charAt(i) - 'a'] = i;
        Deque<Character> stack = new ArrayDeque<>();
        boolean[] seen = new boolean[26];
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (seen[c - 'a']) continue;
            while (!stack.isEmpty() && stack.peek() > c && last[stack.peek() - 'a'] > i) {
                seen[stack.pop() - 'a'] = false;
            }
            stack.push(c);
            seen[c - 'a'] = true;
        }
        StringBuilder sb = new StringBuilder();
        Iterator<Character> it = stack.descendingIterator();
        while (it.hasNext()) sb.append(it.next());
        return sb.toString();
    }
}
string smallestSubsequence(string s) {
    vector<int> last(26, 0);
    for (int i = 0; i < (int)s.size(); i++) last[s[i] - 'a'] = i;
    string stack;
    vector<bool> seen(26, false);
    for (int i = 0; i < (int)s.size(); i++) {
        char c = s[i];
        if (seen[c - 'a']) continue;
        while (!stack.empty() && stack.back() > c && last[stack.back() - 'a'] > i) {
            seen[stack.back() - 'a'] = false;
            stack.pop_back();
        }
        stack.push_back(c);
        seen[c - 'a'] = true;
    }
    return stack;
}
Time: O(n) Space: O(1) (alphabet bounded)