首页 > 代码库 > BNUOJ 44586 顽皮的字母 (栈的应用)

BNUOJ 44586 顽皮的字母 (栈的应用)

顽皮的字母


大家都知道有26个英文字母,abcdef…。由这些字母组成了一个字符串,但是,由于这些字母日久生情,有一些字母挨在一起的时候就会一起跑走玩耍。我们对26个字母编号1~26,就是说1对应a,…,26对应z,第i个字母和第i+1个字母相互有好感,挨在一起会跑开,i为1~26里面的奇数,跑开之后空位由后面的字母补上。现在问题来了,输入一个长度为n(n<10^5)的字符串,这个字符串包含挨在一起的情况比如ab挨在一起,问最后剩下的字符串是什么。

Input

第1行为数据组数T(T<=100)。

第2行到第T+1行为输入字符串,每行一个字符串。

保证输入全为英文小写字母

Output

对于每个字符串,输出一行最后剩下的字符串。如果最后所有的字母都跑开了输出“sad!”,不包括引号。

Sample Input

2
ababababc
abacda

Sample Output

c
aa



解析:由于这个特殊的要求,如果用数组来回扫的话,肯定是超时了。所以我们可以用到栈,这样每个元素只进栈一次,时间就能达到O(n)的。具体实现方法如下:

先把第一个字符入栈,再把剩下的n-1个字符入栈, 每次入栈的时候都判断当前字符和栈顶元素是否满足跑走的条件:即两个字符中的较小的那个在字符表中的位置是奇数,且

两个字符在字母表中位置相邻。如果满足的话,就将栈顶元素出栈;否则,就将该字符入栈。然后重复上述操作,直到将剩下的n-1个字符全部扫一遍为止,最后在栈里面剩的就是剩下的字符串,不过直接弹出的话是倒序的,要调整一下顺序。






AC代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
using namespace std;
#define INF 0x7fffffff
#define LL long long
#define LLL(a, b)  a<<b
#define RRR(a, b)  a>>b
#define MID(a, b)  a+(b-a)/2
const int maxn = 1000 + 10;

int main(){
    #ifdef sxk
        freopen("in.txt", "r", stdin);
    #endif // sxk

    int n;
    string s;
    scanf("%d", &n);
    while(n--){
        char p[100005];
        int foo = 0;
        cin >> s;
        int len = s.size();
        for(int i=0; i<len; i++){
            if(foo && min(p[foo-1] - 'a', s[i] - 'a') % 2 == 0 && abs(p[foo-1] - s[i]) == 1) foo --;       //满足跑走的条件
            else p[foo++] = s[i];                    //不满足条件,字符入栈
        }
        if(!foo)  printf("sad!");
        for(int i=0; i<foo; i++)  cout << p[i];
        cout << endl;
    }
    return 0;
}






BNUOJ 44586 顽皮的字母 (栈的应用)