1. 程式人生 > >51nod 1255 字典序最小的子序列【貪心】

51nod 1255 字典序最小的子序列【貪心】

給出一個由a-z組成的字串S,求他的一個子序列,滿足如下條件:
1、包含字串中所有出現過的字元各1個。 2、是所有滿足條件1的串中,字典序最小的。 例如:babbdcc,出現過的字元為:abcd,而包含abcd的所有子序列中,字典序最小的為abdc。 Input
輸入1行字串S,所有字元均為小寫,字串的長度為L。(1 <= L <= 100000)。
Output
輸出包含S中所有出現過的字元,每個字元各1個,並且字典序最小的S的子序列。
Input示例
babbdcc
Output示例
abdc

思路:

1、我們建立一個棧,用來存放解。

對於這個字串,我們從第一個字元開始掃:

①如果這個棧此時為空,那麼將這個字元丟進去。

②如果棧此時不為空,而且當前這個字元已經在棧中,跳過。

③如果棧此時不為空,而且當前這個字元不在棧中,我們分兩種情況討論:1.如果這個字元比棧頂大,那麼直接丟到棧頂即可。2.如果這個比棧頂小,那麼我們判斷此時棧頂在這個字元後邊還是否存在。如果後邊還有,那麼對應將棧頂彈出,直到不能彈出為止,再將這個字元丟到棧頂。

這樣我們就能做到儘可能的貪心。

2、考慮到我們如果O(n^2)判斷當前字元後邊是否還存在這個字元,是很容易TLE的。所以我們O(n)維護當前這個字元在字串中是第幾次出現的,如果是最後一次,那麼顯然這個字元後邊就不再存在了。這個方法還是很好實現的。

3、過程中細節較多,我們注意千萬要維護好每個字元後邊是否還存在這個字元這個條件。最後將所有字元彈出棧,逆序輸出。

Ac程式碼:

#include<stdio.h>
#include<string.h>
#include<stack>
using namespace std;
char a[100060];
char ans[300];
int use[300];
int have[300];
int num[100060];
int contz[300];
int main()
{
    while(~scanf("%s",a))
    {
        int n=strlen(a);
        memset(contz,0,sizeof(contz));
        memset(num,0,sizeof(num));
        memset(use,0,sizeof(use));
        for(int i=0;i<256;i++)have[i]=1;
        for(int i=0;i<n;i++)
        {
            contz[a[i]]++;
            num[i]=contz[a[i]];
        }
        stack<char >s;
        for(int i=0;i<n;i++)
        {
            if(s.size()==0)
            {
                s.push(a[i]);
                use[a[i]]=1;
                if(num[i]==contz[a[i]])have[a[i]]=0;
            }
            else
            {
                if(use[a[i]]==1)
                {
                    if(num[i]==contz[a[i]])have[a[i]]=0;
                    continue;
                }
                else if(a[i]<s.top())
                {
                    while(!s.empty())
                    {
                        if(a[i]<s.top()&&have[s.top()]==1)
                        {
                            use[s.top()]=0;
                            s.pop();
                        }
                        else break;
                    }
                }
                s.push(a[i]);
                use[a[i]]=1;
                if(num[i]==contz[a[i]])have[a[i]]=0;
            }
        }
        int cont=0;
        while(!s.empty())
        {
            ans[cont++]=s.top();
            s.pop();
        }
        for(int i=cont-1;i>=0;i--)
        {
            printf("%c",ans[i]);
        }
        printf("\n");
    }
}