给出一个由a-z组成的字符串S,求他的一个子序列,满足如下条件:

1、包含字符串中所有出现过的字符各1个。

2、是所有满足条件1的串中,字典序最小的。

例如:babbdcc,出现过的字符为:abcd,而包含abcd的所有子序列中,字典序最小的为abdc。

输入
输入1行字符串S,所有字符均为小写,字符串的长度为L。(1 <= L <= 100000)。
输出
输出包含S中所有出现过的字符,每个字符各1个,并且字典序最小的S的子序列。
输入样例
babbdcc
输出样例
abdc

题目思路:用一个栈来储存答案,从左到右遍历一遍字符串,如果在栈中(有标记)直接continue。如果串中字符小于栈顶且字符串中还有栈顶元素则出栈,且取消标记。(这里应该用while循环,有可能栈中多个元素都要出栈),没有标记的直接进栈,标记。最后倒序输出就是了。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
char s[maxn], ans[maxn];
int cnt[maxn], vis[maxn];
stack<char> st;
int main() {
	scanf("%s", s);
	int n = strlen(s);
	for (int i = 0; i < n; i++) {
		cnt[s[i]]++; //记录数量
	}
	for (int i = 0; i < n; i++) {
		cnt[s[i]]--;
		if (vis[s[i]]) { //如果该字符已经在栈中,直接跳过
			continue;
		}
		while (!st.empty() && st.top() > s[i] && cnt[st.top()] > 0) { //如果当前字符比栈顶元素要小,且当前栈顶元素可以在后面找的到,退栈(取消栈标记)
			vis[st.top()] = 0;
			st.pop();
		}
		st.push(s[i]);
		vis[s[i]] = 1;
		
	}
	int tot = 0;
	while(!st.empty()) {
		ans[++tot] = st.top();
		st.pop();
	}
	for (int i = tot; i >= 1; i--) {
		printf("%c", ans[i]);
	}
	printf("\n");
	return 0;
}