题目传送门:https://ac.nowcoder.com/acm/contest/551#question
题目描述
CSL 以前不会字符串算法,经过一年的训练,他还是不会……于是他打算向你求助。
给定一个字符串,只含有可打印字符,通过删除若干字符得到新字符串,新字符串必须满足两个条件:
- 原字符串中出现的字符,新字符串也必须包含。
- 新字符串中所有的字符均不相同。
- 新字符串的字典序是满足上面两个条件的最小的字符串。
输入描述:
仅一行,有一个只含有可打印字符的字符串 s。
|s|≤105|s|≤105
输出描述:
在一行输出字典序最小的新字符串。
备注:
ASCII字符集包含 94 个可打印字符(0x21 - 0x7E),不包含空格。
解题思路:
贪心,用一个栈逆序保存答案,第一次扫一遍字符串,记录每一个字符最后出现的位置(用于判断栈内元素是否为该类字符的最后那个字符)。
第二次扫一遍字符串,如果比栈顶元素大或者当前空栈,压栈。否则,如果栈顶的元素比当前元素大并且不是该元素最后的元素,即后面还有栈顶这种元素,那么栈顶元素出栈。
最后逆序输出栈内元素。
AC code:
1 #include <bits/stdc++.h> 2 #define INF 0x3f3f3f3f 3 #define LL long long 4 #define inc(i, j, k) for(int i = j; i <= k; i++) 5 #define rep(i, j, k) for(int i = j; i < k; i++) 6 #define mem(i, j) memset(i, j, sizeof(i)) 7 #define gcd(i, j) __gcd(i, j) 8 using namespace std; 9 10 const int MAXN = 2e5+10; 11 string str; 12 stack<char>ss; 13 map<char, int>mmp; 14 string ans; 15 map<char, bool>vis; 16 int main() 17 { 18 cin >> str; 19 int len = str.size(); 20 rep(i, 0, len){ 21 mmp[str[i]]=i; 22 } 23 24 25 rep(i, 0, len){ 26 if(!vis[str[i]]){ 27 if(ss.empty() || str[i] > ss.top()){ 28 vis[str[i]] = true; 29 ss.push(str[i]); 30 continue; 31 } 32 while(!ss.empty() && ss.top() > str[i] && mmp[ss.top()] > i){ 33 vis[ss.top()] = false; 34 ss.pop(); 35 } 36 //puts("zjj"); 37 ss.push(str[i]); 38 vis[str[i]] = true; 39 } 40 } 41 while(!ss.empty()){ 42 // printf("%c", ss.top()); 43 ans+=ss.top(); 44 ss.pop(); 45 } 46 for(int i = ans.size()-1; i >= 0; i--) 47 printf("%c", ans[i]); 48 puts(""); 49 return 0; 50 }