给定一个最大容量为 M 的堆栈,将 N 个数字按 1, 2, 3, ..., N 的顺序入栈,允许按任何顺序出栈,则哪些数字序列是不可能得到的?例如给定 M=5、N=7,则我们有可能得到{ 1, 2, 3, 4, 5, 6, 7 },但不可能得到{ 3, 2, 1, 7, 5, 6, 4 }。
输入格式:
输入第一行给出 3 个不超过 1000 的正整数:M(堆栈最大容量)、N(入栈元素个数)、K(待检查的出栈序列个数)。最后 K 行,每行给出 N 个数字的出栈序列。所有同行数字以空格间隔。
输出格式:
对每一行出栈序列,如果其的确是有可能得到的合法序列,就在一行中输出YES
,否则输出NO
。
输入样例:
5 7 5
1 2 3 4 5 6 7
3 2 1 7 5 6 4
7 6 5 4 3 2 1
5 6 4 3 7 2 1
1 7 6 5 4 3 2
输出样例:
YES
NO
NO
YES
NO
模拟K个进栈出栈的过程,看是否可以完成
1.当前元素是栈顶元素,出栈
while(j<n&&v[j]==M.top())
{//如果栈顶元素和当前需打印元素相等,就出栈
M.pop();
j++;
}
2.当前元素大于栈顶元素,执行进栈操作,直到进栈元素与当前元素相等
基于此题的限制,在每个元素进栈前要进行栈空间的判断,如果栈满,则此过程失败
if(M.top()<v[j])
{//如果当前元素小于栈顶元素
while(now<=v[j])
{//入栈now
M.push(now);
now++;
if(M.size()>m+1)
{//判断是否栈满
flag=0;
break;
}
}
M.pop();//出栈
}
3.当前元素小于栈顶元素,此过程失败
if(M.top()>v[j])
{//如果当前元素小于栈顶元素,直接否认
//因为不可能让这个小的元素先出栈了
flag=0;
break;
}
4.如何完成以上的过程
(1)首先压入一个元素作为标记,以进行第一次判断
(2)按照1234编写if语句
(3)最外层的循环:模拟的过程中主要变化的是待检序列,按照正常情况应该要判断到最后一个元素,所以用待检序列作为外层循环
(4)进栈是按照123……的顺序,所以设置一个标记数now来记录已经进栈的元素
5.完整代码
#include <iostream>
using namespace std;
#include <stack>
int v[1001]; // 存放待检序列
int main()
{
int m, n, k;
cin >> m >> n >> k;
for (int i = 0; i < k; i++)
{
for (int j = 0; j < n; j++)
cin >> v[j];
stack<int> M; // 栈
int flag = 1, now = 1;
M.push(0); // 标记
for (int j = 0; j < n; j++)
{//j是要判断的元素下标
while (j < n && v[j] == M.top())
{ // 如果栈顶元素和当前需打印元素相等,就出栈
M.pop();
j++;
}
if (M.top() > v[j])
{ // 如果当前元素小于栈顶元素,直接否认
// 因为不可能让这个小的元素先出栈了
flag = 0;
break;
}
if (M.top() < v[j])
{ // 如果当前元素小于栈顶元素
while (now <= v[j])
{ // 入栈now
M.push(now);
now++;
if (M.size() > m + 1)
{ // 判断是否栈满
flag = 0;
break;
}
}
M.pop(); // 出栈
}
if (flag == 0)
break;//针对栈满时的flag设立
}
if (flag == 1)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
}