题目链接
假设以S和X分别表示入栈和出栈操作。如果根据一个仅由S和X构成的序列,对一个空堆栈进行操作,相应操作均可行(如没有出现删除时栈空)且最后状态也是栈空,则称该序列是合法的堆栈操作序列。请编写程序,输入S和X序列,判断该序列是否合法。
输入格式:
输入第一行给出两个正整数N和M,其中N是待测序列的个数,M(≤50)是堆栈的最大容量。随后N行,每行中给出一个仅由S和X构成的序列。序列保证不为空,且长度不超过100。
输出格式:
对每个序列,在一行中输出YES如果该序列是合法的堆栈操作序列,或NO如果不是。
输入样例:
4 10
SSSXXSXXSX
SSSXXSXXS
SSSSSSSSSSXSSXXXXXXXXXXX
SSSXXSXXX
输出样例:
YES
NO
NO
NO
这道题其实考察的是栈的应用,考察了栈的入栈操作, 出栈操作, 以及判断栈是否Full , 以及是否栈空删除 , 这是栈的基本操作
这是栈的定义
typedef int ElementType;
typedef enum { push, pop, end } Operation;
typedef enum { false, true } bool;
typedef int Position;
typedef struct SNode *PtrToSNode;
struct SNode {
ElementType *Data; /* 存储元素的数组 */
Position Top; /* 栈顶指针 */
int MaxSize; /* 堆栈最大容量 */
};
typedef PtrToSNode Stack;
下面是入栈的模板, 我们可以看到每次加入一个新的元素 , 都会加入到栈的尾部 ,如果达到栈的最大空间则就输出Stack Full 。
注意:栈是一种插到尾部,然后优先从尾部取出元素。
bool Push( Stack S, ElementType X )
{
if(S -> Top == S -> MaxSize)
{
puts("Stack Full") ;
return false ;
}
S -> Data[(S -> Top) ++] = X ;
return true ;
}
然后是出栈的模板,这里第一步先判断栈是否为空, 从尾部删掉节点, 然后完成栈的删除操作 。
ElementType Pop( Stack S )
{
if(S -> Top == 0)
{
puts("Stack Empty") ;
return ERROR ;
}
return S -> Data[-- (S -> Top)] ;
}
这里我们想一想怎么去进行差分操作。
首先,我们要是想满足栈为空的时候不被删除,首先我们想想,我们一定要满足S的数量大于X才行。
为什么 ?
因为加的元素比删的元素多才能满足上述条件 , 同时,不应该只针对最后一个下标满足此要求, 而是针对所有下标都应满足S的数量大于X 。
第二我们考虑一下怎么解决栈满问题, 我们有一个关键思维, 就是把 S 看成1 , X 看成 -1 , 然后对其进行求前缀和, 其前缀和就是当前栈里面存的元素的数量, 然后前缀和也不应该大于栈的空间。
第三最后满足完成所有的操作之后 , 栈为空 , 第二个条件我们可知 ,其前缀和就是当前栈里面存的元素的数量 , 我们是否可以根据前缀和为0 来 得出当前栈里面有几个元素。
没错, 是的, 如果最后一个元素的前缀和为0 , 则我们说他满足要求 , 反之则不满足要求 。
第一步我们先输入数据, 对其进行求前缀和, 把 S 看成 1 , X 看成 -1 。
scanf("%s" , s) ;
int len = strlen(s) ;
for(int i = 1 ; i <= len ; i ++) pre[i] = pre[i - 1] + ((s[i - 1] == 'S') ? 1 : - 1) ;
第三句同下段代码作用相同
for(int i = 1 ; i <= len ; i ++)
if(S[i - 1] == 'S')
pre[i] = pre[i - 1] + 1 ;
else
pre[i] = pre[i - 1] - 1 ;
第二
然后我们开始遍历前缀和,如果前缀小于0 , 或者大于m则不满足条件(解释上文所示)
bool success = true ;
for(int i = 1 ; i <= len ; i ++)
if(pre[i] < 0 || pre[i] > m)
{
success = false ;
break ;
}
第三
我们判断最后一个条件
if(pre[len] != 0) success = false ;
最后整个代码如下
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std ;
const int N = 1e5 + 10 ;
int pre[N] ;
int main(void)
{
int T , m ;
char s[N] ;
scanf("%d%d" , &T , &m) ;
while(T --)
{
scanf("%s" , s) ;
int len = strlen(s) ;
for(int i = 1 ; i <= len ; i ++) pre[i] = pre[i - 1] + ((s[i - 1] == 'S') ? 1 : - 1) ;
bool success = true ;
for(int i = 1 ; i <= len ; i ++)
if(pre[i] < 0 || pre[i] > m)
{
success = false ;
break ;
}
if(pre[len] != 0) success = false ;
if(success) puts("YES") ;
else puts("NO") ;
}
}