顽皮的字母
大家都知道有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;
}