1057. Stack (30)-PAT甲级真题

实现一种栈,它可以快速查找堆栈中所有元素的中值。对于N个元素,若N是偶数,则中值定义为第N/2个最小元素;若N是奇数,则中值定义为第(N+1)/2个最小元素

用快排三个测试点超时不过,做不出来。

看了柳神的树状数组+二分查找解法后学习了一种高级数据结构:树状数组,在面对动态数据流的时候区间查询和修改都只要(O(logn)),强烈推荐这篇:树状数组(详细分析+应用),看不懂打死我!

除此之外,问了GPT,GPT给出了个求中位数的好方法,使用大根堆和小根堆,个人觉得非常巧妙,操作的时间复杂度都只要O(logn):

以下是通过小根堆和大根堆来找到中位数的思路:

  1. 使用两个堆:

    • 大根堆(max-heap): 存储较小的一半数据,堆顶是这一部分的最大值。
    • 小根堆(min-heap): 存储较大的一半数据,堆顶是这一部分的最小值。
  2. 平衡堆:

    • 当插入一个新元素时,如果它比大根堆的堆顶小,插入大根堆;否则插入小根堆。
    • 插入后,如果两个堆的大小相差超过1,则将多余元素从较大的堆中移动到较小的堆中,以保持两个堆的平衡。
  3. 查找中位数:

    • 如果两个堆的大小相同,中位数是两个堆顶的平均值。
    • 如果堆的大小不同,中位数是元素更多的那个堆的堆顶。

我按照这个思路尝试实现了下,发现能过,这里如果直接用priority_queue的话,由于priority_queue不能直接删除特定元素,不是很方便,所以这里用multiset来表示大小根堆(minHeap.begin()的元素在minHeap中最小,prev(maxHeap.end())的元素在maxHeap中最大)

AC代码:

#include <bits/stdc++.h>
using namespace std;
stack<int> s;
multiset<int> maxHeap, minHeap;
void pushNum(int num)
{
    if (maxHeap.empty() || num <= (*prev(maxHeap.end())))
        maxHeap.insert(num);
    else
        minHeap.insert(num);
    if (maxHeap.size() > minHeap.size() + 1)
    { // 调整
        minHeap.insert(*prev(maxHeap.end()));
        maxHeap.erase((prev(maxHeap.end())));
    }
    else if (minHeap.size() > maxHeap.size())
    {
        maxHeap.insert(*minHeap.begin());
        minHeap.erase(minHeap.begin());
    }
}
void popNum(int num)
{
    if (num <= (*prev(maxHeap.end())))
        maxHeap.erase(maxHeap.find(num));
    else
        minHeap.erase(minHeap.find(num));
    if (maxHeap.size() > minHeap.size() + 1)
    { // 调整
        minHeap.insert(*prev(maxHeap.end()));
        maxHeap.erase(prev(maxHeap.end()));
    }
    else if (minHeap.size() > maxHeap.size())
    {
        maxHeap.insert(*minHeap.begin());
        minHeap.erase(minHeap.begin());
    }
}

int main()
{
    int n, key;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
    {
        char str[15];
        scanf("%s", &str);
        if (str[1] == 'o')
        {
            if (s.empty())
                printf("Invalid\n");
            else
            {
                printf("%d\n", s.top());
                popNum(s.top());
                s.pop();
            }
        }
        else if (str[1] == 'u')
        {
            scanf("%d", &key);
            pushNum(key);
            s.push(key);
        }
        else
        {
            if (s.empty())
                printf("Invalid\n");
            else
            {
                printf("%d\n", (*prev(maxHeap.end())));
            }
        }
    }
}
  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值