51-Nod 1255字典序最小子序列(贪心)

字典序最小的子序列

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

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

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

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

输入

输入1行字符串S,所有字符均为小写,字符串的长度为L。(1 <= L <= 100000)。

输出

输出包含S中所有出现过的字符,每个字符各1个,并且字典序最小的S的子序列。

输入样例
babbdcc
输出样例
abdc
链接:

http://www.51nod.com/Challenge/Problem.html#!#problemId=1255

思路:

贪心。可以用栈来存答案,首先把每个字符出现的最后位置记录下来。然后从左到右开始找,如果栈顶元素大于现在元素并且栈顶元素在后面还有(即栈顶元素的最后位置>i),那么出栈,取消标记(这里用while循环,有可能栈中有好几个元素需要出栈)。没有标记的直接进栈,标记。最后倒序输出。。

代码:
#include
using namespace std;
const int maxn = 1e5+10;
int last[maxn];
bool vis[maxn];
int main()
{
    string p;
    cin >> p;
    int len = p.length();
    stack<int > s;
    while(!s.empty()){
        s.pop();
    }
    for(int i = 0; i < len; i++) {
        int k = p[i];
        if(last[k] < i)
            last[k] = i;
    }
    for(int i = 0; i < len; i++) {
        int k = p[i];
        if(vis[k]) {   //别忘判断是否被标记,标记直接跳过即可。
            continue;
        }
        while(!s.empty() && last[s.top()] > i && k <= s.top()) {
            vis[s.top()] = 0;
            s.pop();
        }
        if(!vis[k]) {
            vis[k] = 1;
            s.push(k);
        }

    }
    int ans[maxn];
    int tot = 0;
    while(!s.empty())
    {
        ans[tot++] = s.top();
        s.pop();
    }
    for(int i = tot-1; i >= 0; i--) {
        printf("%c", ans[i]);
    }
    return 0;
}

你可能感兴趣的:(贪心)