https://www.51nod.com/Challenge/Problem.html#!#problemId=1255
给出一个由a-z组成的字符串S,求他的一个子序列,满足如下条件:
1、包含字符串中所有出现过的字符各1个。 2、是所有满足条件1的串中,字典序最小的。
例如:babbdcc,出现过的字符为:abcd,而包含abcd的所有子序列中,字典序最小的为abdc。 输入 输入1行字符串S,所有字符均为小写,字符串的长度为L。(1 <= L <= 100000)。 输出 输出包含S中所有出现过的字符,每个字符各1个,并且字典序最小的S的子序列。 输入样例 babbdcc 输出样例 abdc
从前往后遍历字符串,维护一个栈。如果当前字符串 c 小于栈顶且不在栈内,且栈顶字符在后面还有出现,则弹栈并将 c 入栈,依次循环直到不符合条件。 如果当前字符已经在栈内,则跳过。 如果 c 大于栈顶,且不在栈内,则入栈,否则跳过。 用两个数组维护字符还剩余的个数 和 是否已在栈内。 总结:入栈两种情况(+第一个字符), 出栈一种,其余的跳过。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #include <cstdio> #include <cstring> #include <set> #include <iostream> #include <queue> #include <stack> #include <algorithm> using namespace std ;#define MAX 100000+10 #define INF 0x3f3f3f3f char a[MAX]; int t[150 ],flag[150 ];char s[27 ],c;int h=0 ,l;int main () { freopen("in" ,"r" ,stdin ); int k=-1 ; while ((c=getchar())!='\n' ){ a[++k]=c; t[c]++; } a[++k]='\0' ; s[0 ]=150 ; l=strlen (a); for (int i=0 ;i<l;i++){ if (!h){ s[++h]=a[i]; flag[a[i]]=1 ; } if (flag[a[i]]){ t[a[i]]--; continue ; } if ( (a[i]<s[h] && !t[s[h]]) || a[i]>s[h] ){ s[++h]=a[i]; flag[a[i]]=1 ; } else if (a[i]<s[h] && t[s[h]] ){ flag[s[h]]=0 ; s[h]=a[i]; flag[a[i]]=1 ; while (a[i]<s[h-1 ] && t[s[h-1 ]]){ h--; flag[s[h]]=0 ; s[h]=a[i]; } } t[a[i]]--; } s[++h]='\0' ; puts (s+1 ); return 0 ; }