【数据结构PTA-栈与队列-3-7-3】

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. 将1,2…n的顺序入栈

  2. 先用一个数组储存出栈顺序

  3. 依次对比,如果数组的值与栈顶元素相同就出栈

  4. 最后观察栈是否为空并且数组同时遍历完成

核心代码

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 辅助学习。

还要试着自己实现核心代码哦,说不定会有更新更好的代码!

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值