1. Recursive Greedy Selection
Intuition
Count character frequencies in s. Find the index of the first character c that can be safely selected (i.e. all other distinct characters still appear at or after this index). Pick the smallest such character, remove all occurrences of it from the remaining suffix, and recurse.
When to apply: Basic functional recursive solution.
Algorithm
- If
sis empty, return"". - Count character frequencies.
- Find the leftmost index
poswhere remaining suffix covers all unique characters. - Pick
minChar = s[pos]. - Filter
minCharfroms.substr(pos + 1)and recurse. - Return
minChar + recurse(filteredSuffix).
Recursive Greedy Selection
2 of 2 questions left todayObservation: Count occurrences of all characters: 'b' appears 2 times, 'c' appears 2 times, 'a' appears 1 time
Observation: Count occurrences of all characters: 'b' appears 2 times, 'c' appears 2 times, 'a' appears 1 time.
Decision: Smallest letter in alphabet is 'a' (at index 2). Suffix after index 2 contains 'b' and 'c', so all remaining letters can still be formed! Pick 'a'.
Invariant: Always pick the lexicographically smallest character whose suffix contains all remaining unique characters.
#include <iostream>#include <string>#include <vector>#include <algorithm> class Solution {public: std::string removeDuplicateLetters(std::string s) { if (s.empty()) return ""; int count[26] = {0}; for (char c : s) count[c - 'a']++; int pos = 0; for (int i = 0; i < (int)s.size(); ++i) { if (s[i] < s[pos]) pos = i; if (--count[s[i] - 'a'] == 0) break; } char chosen = s[pos]; std::string remainder = s.substr(pos + 1); remainder.erase(std::remove(remainder.begin(), remainder.end(), chosen), remainder.end()); return chosen + removeDuplicateLetters(remainder); }}; int main() { Solution sol; std::cout << sol.removeDuplicateLetters("bcabc") << std::endl; // "abc" std::cout << sol.removeDuplicateLetters("cbacdcbc") << std::endl; // "acdb" return 0;}Time & Space Complexity
- Time complexity:
O(26 * N)— At most 26 recursive levels, each scanning suffix of length up to N. - Space complexity:
O(26 * N) recursion stack
Why Brute Force Doesn't Scale:
Monotonic stack evaluates and resolves character order in a single linear pass.
Using 26-element integer and boolean arrays guarantees O(1) auxiliary space.