Problem
Given a stack which can keep M numbers at most. Push N numbers in the order of 1, 2, 3, …, N and pop randomly. You are supposed to tell if a given sequence of numbers is a possible pop sequence of the stack. For example, if M is 5 and N is 7, we can obtain 1, 2, 3, 4, 5, 6, 7 from the stack, but not 3, 2, 1, 7, 5, 6, 4.
意思就是说有一个栈,最大为M,输入K个从1到N的乱序。然后判断这个序列是不是该栈的合法输出。
Input Specification:
Each input file contains one test case. For each case, the first line contains 3 numbers (all no more than 1000): M (the maximum capacity of the stack), N (the length of push sequence), and K (the number of pop sequences to be checked). Then K lines follow, each contains a pop sequence of N numbers. All the numbers in a line are separated by a space.
输入时,第一行是三个数字,都小于1000,M表示栈最大的容量,N表示乱序序列的长度,K表示有几个乱序序列。每个数字之间都用一个空格分隔。
Output Specification:
For each pop sequence, print in one line “YES” if it is indeed a possible pop sequence of the stack, or “NO” if not.
输出YES表示是栈的合法输出,输出NO表示非法输出。
My Solution
我的思路是这样的:
对每一个序列,
第一个数如果大于M,输出序列非法,否则入栈。
然后从第二个元素开始比较,如果这个元素比栈顶的元素大,那么这个元素与栈顶元素的差必须小于等于M,否则该序列非法。
如果这个元素比栈顶元素小,那么它必须是这N个元素里面还未出现的最大元素,否则该序列非法。
(我个人觉得没问题,但是不能的满分,PAT得24分,差一分。欢迎指正。)
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstring>
#include <map>
#include <iterator>
using namespace std;
#pragma warning(disable:4996)
int main()
{
stack<int>b;
int m = 0;
int n = 0;
int k = 0;
cin >> m >> n >> k;
int c[1000][1000] = { 0 };
bool d[1000] = { 0 };
queue<int*>a; //队列的元素是大小为n的数组
if (m < 0 || m>1000) {
return -1;
}
if (n < 0 || n>1000) {
return -1;
}
if (k < 0 || k>1000) {
return -1;
}
for (int i = 0; i < k; i++) {
for (int j = 0; j < n; j++) {
cin >> c[i][j];
}
a.push(c[i]);
}
for (int i = 0; i < k; i++) {
while (!b.empty()) { b.pop(); }
memset(d, 0, 1000);
if (a.front()[0] > m) {
cout << "NO" << endl;
}
else {
b.push(a.front()[0]);
d[a.front()[0] - 1] = true;
for (int j = 1; j < n; j++) {
if (a.front()[j] > b.top()) {
if (a.front()[j] - b.size() <= m && j == 6) { cout << "YES" << endl; break; }
if (a.front()[j] - b.size() <= m) { b.push(a.front()[j]); d[a.front()[j] - 1] = true; }
else { cout << "NO" << endl; break; }
}
else if (a.front()[j] < b.top()) {
int i1 = 0;
for (i1 = b.top() - 1; i1 >= 0; i1--) {
if (d[i1] == false) break;
}
if (i1 > -1) { //此处这个if其实可以省略,这里的每个数都会出现。
if (a.front()[j] == i1 + 1 && j == 6) { cout << "YES" << endl; break; }
if (a.front()[j] == i1 + 1) { b.push(a.front()[j]); d[a.front()[j] - 1] = true; }
else { cout << "NO" << endl; break; }
}
else { cout << "NO" << endl; break; }
}
else { cout << "NO" << endl; break; } //这个else也可以不要。
}
}
a.pop();
}
return 0;
}
我这里采用的是先把输入全部完成,存储所有的输入,然后开始一个一个计算,但是,其实不需要这样也可以。不用存储所有的输入,输入一个计算一个也可以。算法笔记解这道题采用的就是这个方法。
算法笔记的解法
思路:让1-n按顺序入栈,如果当前刚入栈的数和输入序列的当前指针指向的数相等,则刚入栈的数出栈,并且输入序列的指针后移一位。如果入栈后,栈的大小大于M了,就返回错误。
#include <cstdio>
#include <stack>
using namespace std;
const int maxn = 1010;
int arr[maxn];
stack<int> st;
int main() {
int m, n, T;
scanf("%d%d%d", &m, &n, &T); //这里没有判断输入是否合法,PAT有时会考虑这个。
while(T--) {
while(!st.empty()) {
st.pop();
}
for(int i = 1; i <= n; i++) {
scanf("%d", &arr[i]);
}
int current = 1;
bool flag = true;
for(int i = 1; i <= n; i++) {
st.push(i);
if(st.size() > m) {
flag = false;
break;
}
while(!st.empty() && st.top() == arr[current]) {
st.pop();
current++;
}
}
if(st.empty() == true && flag == true) {
printf("YES\n");
} else {
printf("NO\n");
}
}
return 0;
}
这个方法是满分,并且比我的简单,他利用栈来实现判断,其实和我的思路本质上是一样的,只是他的更加精简。
谢谢阅读!