3-7-3 出栈序列的合法性
题目
题目描述
给定一个最大容量为 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
。
解题难点
如何判断出栈序列的合法性?
可以通过一一对比的方式,如果对比结束,栈为空说明序列合法
=>
-
将1,2…n的顺序入栈
-
先用一个数组储存出栈顺序
-
依次对比,如果数组的值与栈顶元素相同就出栈
-
最后观察栈是否为空并且数组同时遍历完成
核心代码
nextPush
: 由于题目描述,因此用这个变量的自增将元素顺序入栈
i
:用于遍历数组
第一个while循环主要为了解决入栈的同时会有元素出栈的情况
第二个while循环主要是 解决单一出栈的情况
int isPossible(int m, int n, int *sequence) {
Stack *s = createStack(m);
int nextPush = 1;
int i = 0;
while (i < n) {
if (s->top != -1 && s->stack[s->top] == sequence[i]) {
i++;
pop(s);
} else if (nextPush <= n) {
push(s, nextPush++);//顺序入栈,因此自增
} else {
break;
}
}
while (i < n && s->top != -1 && s->stack[s->top] == sequence[i]) {
i++;
pop(s);
}
free(s->stack);
free(s);
return (i == n);
}
小问题
有同学和我讨论过 “为什么栈的最大容量小于元素总量”
我是这么想的:入栈和出栈可以是动态进行的,不是需要所有元素都能同时存在栈中。这也是第一个while循环存在的意义。
完整题解
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 1000
typedef struct {
int *stack;
int top;
int MaxSize;
} Stack;
Stack *createStack(int MaxSize) {
Stack *s = (Stack *)malloc(sizeof(Stack));
s->MaxSize = MaxSize;
s->top = -1;
s->stack = (int *)malloc(sizeof(int) * MaxSize);
return s;
}//init
void push(Stack *s, int t) {
if (s->top == s->MaxSize - 1) {
return 0;//stack full
}
s->stack[++s->top] = t;
}
int pop(Stack *s) {
if (s->top == -1) {
return 0;//stack empty
}
return s->stack[s->top--];
}
int isPossible(int m, int n, int *sequence) {
Stack *s = createStack(m);
int nextPush = 1;
int i = 0;
while (i < n) {
if (s->top != -1 && s->stack[s->top] == sequence[i]) {
i++;
pop(s);
} else if (nextPush <= n) {
push(s, nextPush++);
} else {
break;
}
}
while (i < n && s->top != -1 && s->stack[s->top] == sequence[i]) {
i++;
pop(s);
}
free(s->stack);
free(s);
return (i == n);
}
int main() {
int m, n, k;
scanf("%d %d %d", &m, &n, &k);
for (int i = 0; i < k; i++) {
int *sequence = (int *)malloc(sizeof(int) * n);
for (int j = 0; j < n; j++) {
scanf("%d", &sequence[j]);
}//save arr
if (isPossible(m, n, sequence)) {
printf("YES\n");
} else {
printf("NO\n");
}
free(sequence);
}
return 0;
}
代码阅读 小tips
先阅读 main函数了解整体逻辑,再细细看具体代码块的实现。将整个代码分开看,结合注释,不懂的可以用 chatGPT
辅助学习。
还要试着自己实现核心代码哦,说不定会有更新更好的代码!