1057 Stack (30point(s)) - PAT 甲级 C语言

1057 Stack (30point(s))

Stack is one of the most fundamental data structures, which is based on the principle of Last In First Out (LIFO). The basic operations include Push (inserting an element onto the top position) and Pop (deleting the top element). Now you are supposed to implement a stack with an extra operation: PeekMedian – return the median value of all the elements in the stack. With N elements, the median value is defined to be the (N/2)-th smallest element if N is even, or ((N+1)/2)-th if N is odd.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N (≤ 105). Then N lines follow, each contains a command in one of the following 3 formats:

Push key
Pop
PeekMedian

where key is a positive integer no more than 105.

Output Specification:

For each Push command, insert key into the stack and output nothing. For each Pop or PeekMedian command, print in a line the corresponding returned value. If the command is invalid, print Invalid instead.

Sample Input:

17
Pop
PeekMedian
Push 3
PeekMedian
Push 2
PeekMedian
Push 1
PeekMedian
Pop
Pop
Push 5
Push 4
PeekMedian
Pop
Pop
Pop
Pop

Sample Output:

Invalid
Invalid
3
2
2
1
2
4
4
5
3
Invalid

题目大意:

实现一种栈,Push 栈顶入栈,Pop 栈顶出栈,PeekMedian 查询栈中所有元素的中值,

如果栈中有 N 个元素,若 N 为偶数,中值为第 (N / 2) 个最小值,若 N 为奇数,中值为第 ((N + 1) / 2) 个最小值

设计思路:

关键词:树状数组,二分查找

  1. 中值即为中位数,对元素排序,返回中间值即可,简单但会超时。

  2. 如何让元素有序并能记录所在位置呢?可以用额外的数组,数组下标代表元素值,数组存储此元素出现的次数,查询中位数时累加各元素次数即可,但依旧耗时。

  3. 利用树状数组,数组下标依旧代表元素值,但树状数组存储的可以看作是小于等于此元素值的元素出现的总次数,此时数组可以看作递增有序,然后利用二分快速查找符合条件的总次数

  • 最终思路利用树状数组和二分查找快速定位中位数
    • 树状数组 bit[],
    • bit_sum(x) 获取小于等于当前元素 x 的出现总次数,
    • 二分查找快速定位 bit_sum(x) >= N / 2 的位置

Reference:

编译器:C (gcc)
#include <stdio.h>

#define MAX 100000

int stk[MAX], top = -1;
int bit[MAX];

int lowbit(int x)
{
        return x & (-x);
}

void bit_edit(int i, int delta)
{
        for (; i < MAX; i += lowbit(i))
                bit[i] += delta;
}

int bit_sum(int i)
{
        int sum = 0;
        for (; i > 0; i -= lowbit(i))
                sum += bit[i];
        return sum;
}

int peek_median()
{
        if (top == -1)
                return -1;
        int left = 0, right = MAX, k = top / 2 + 1;
        int sum, mid;

        while (left < right) {
                mid = (left + right) / 2;
                sum = bit_sum(mid);
                if (sum >= k)
                        right = mid;
                else
                        left = mid + 1;
        }
        return left;
}

int push(int x)
{
        if (top == MAX - 1)
                return -1;
        stk[++top] = x;
        bit_edit(x, 1);
        return x;
}

int pop()
{
        if (top == -1)
                return -1;
        bit_edit(stk[top], -1);
        return stk[top--];
}

int main(void)
{
        char op[11];
        int n, key;
        int i, ans;

        scanf("%d", &n);
        for (i = 0; i < n; i++) {
                scanf("%s", op);
                if (op[1] == 'u') {
                        scanf("%d", &key);
                        ans = push(key);
                        if (ans == -1)
                                printf("Invalid\n");
                } else if (op[1] == 'o') {
                        ans = pop();
                        if (ans == -1)
                                printf("Invalid\n");
                        else
                                printf("%d\n", ans);
                } else {
                        ans = peek_median();
                        if (ans == -1)
                                printf("Invalid\n");
                        else
                                printf("%d\n", ans);
                }
        }
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值