Description

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

1、包含字符串中所有出现过的字符各1个。
2、是所有满足条件1的串中,字典序最小的。

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

Solution

一开始看到这题就有一个思路:如果现在找出来的答案末尾是x,找到了一个字符y,那么如果y比x要小,y后面还有x存在,那么就用y去替换掉x。
搞了好久之后,发现这个有问题啊!!!
看了看题解之后,发现题解与我的想法很像,但是我的想法还是有一点漏洞:找在答案末尾一直找,直到不能替换为止,所以要打一个栈。
然后栈从下到上就是答案。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=100007;
int i,j,k,n,m,ans;
int hou[maxn][26];
char s[maxn],ans1[100],ch;
bool bz[26];
stack<char> t;
int main(){
scanf("%s",s+1);n=strlen(s+1);
fod(i,n,1){
fo(j,0,25){
hou[i][j]=hou[i+1][j];
}
hou[i][s[i]-'a']++;
}
fo(i,1,n){
if(t.empty())t.push(s[i]),bz[s[i]-'a']=1;
else{
while(!t.empty()&&t.top()>=s[i]&&hou[i][t.top()-'a']&&!bz[s[i]-'a']){
bz[t.top()-'a']=0;
t.pop();
}
if(!bz[s[i]-'a'])t.push(s[i]),bz[s[i]-'a']=1;
}
}
while(!t.empty())ans1[++ans]=t.top(),t.pop();
fod(i,ans,1)putchar(ans1[i]);
}