PAT 1057

时间:2023-02-10 17:53:26

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

算法思路

本题考查的是动态中位数的算法, 并且注意到这题时间限制是150ms,意味着至少得使用\(O(n)\)的算法,否则一定

关于中位数

当数组长度为N, 是中位数一般被定义为$ (N+1)/2 $,找中位数的算法简单想了一下, 有以下几种

  • 排序后取[(N + 1)/2]的值,几乎是万能的,即使是频繁更新这个方法也适用,但是复杂度比较高,\(\log_{2}N\), 每次都需要排序,这题是行不通的
  • 网上看到有使用两个堆, 一个大根堆, 一个小根堆,大根堆存小于中位数的数, 小根堆存大于中位数的数,因此只要保持两个堆的数字数量相差不超过1, 那么大根堆的堆顶就是中位数。然后初始化一个中位数,每当插入一个数的时候,若大于这个中位数,插入小根堆, 若小于中位数,插入大根堆,接着如果不满足数量平衡,再从一个堆的顶部拿出来一个数加入另一个堆即可。

    分析:插入操作复杂度为\(O(\log N)\), 调整也是\(O(\log N)\),取出也是\(O(\log N)\),因此速度还是可以的,如果需要执行pop,可以从堆中删除一个数,复杂度同样也是\(O(\log N)\)
  • 这里看到一种新的数据结构:树状数组,参考网上众多博客后发现这篇 搞懂树状数组 写的比较清楚,先mark一下,需要熟悉一下树状数组的基本思想才能理解以后更好的运用,希望以后自己也能总结出一篇这样的文章来。

回到题目

总结一下这题的算法, 使用树状数组的最直接的好处是在频繁更新的数组中很容易的计算出一个连续区间[1,n]的和, 有了这个性质, 当然也可以计算出任意区间[m, n]的和, 只需要减一下就行了, 计算和插入速度都是log的,那么如何使用这个性质找到中位数呢?

首先我们有这么几个数:

A 1 1 2 3 4 4 5 6
index 0 1 2 3 4 5 6 7

可以得到一个count数组

index 0 1 2 3 4 5 6
count 0 2 1 1 2 1 1

现在计算sum(0, 4) = 4就能知道数组中小于等于4的整数有(2 + 1 + 1 + 1) = 6个, 我们知道如果这个答案等于(N+1)/2这个index就是我们需要的中位数,但是我们需要从0开始遍历每一个index让后求出sum(0, index)来找到sum=4的位置吗, 那么最坏情况是要找n次。好在sum数组有一个很好的性质——非递减数组,也就是sum(i)天生就是排好序的(当然这只适用于没有负数的情况),我们可以使用一个二分查找很快的找到sum(i) = 4 的i于是就是这题的思路了。

PS:在二分查找的时候会遇到一些问题,这里有一个例子

A 1 1 2 3 5 6 100 100
index 0 1 2 3 4 5 6 7
index 0 1 2 3 4 5 6 ... 100
count 0 2 1 1 0 1 1 ... 2

这样算出来sum(0, 3) 和sum(0, 4)都等于4, 然而我们只需要的是最左边的4(很显然, 4并没有存在于我们的数组),因此有一个必须做到的是必须用binsearch找到最左边的4,这里需要注意,看完这篇博客二分查找技巧以后, 感觉自己没学过二分查找似的,还是要努力学习:

最后上源码:

#include <stdio.h>
#include <string.h> using namespace std; const int MAX = 100005; int cnt[MAX];
int N;
int stack[MAX];
int len = -1; void init()
{
memset(cnt, 0, sizeof(cnt));
}
void add(int pos, int delt)
{
while(pos <= MAX)
{
cnt[pos] += delt;
pos += pos&-pos;
}
}
int sum(int i)
{
int s = 0;
while(i)
{
s += cnt[i];
i -= i&-i;
}
return s;
}
void push()
{
int key;
scanf("%d", &key);
stack[++len] = key;
add(key, 1);
}
void pop()
{
if(len == -1)
{
printf("Invalid\n");
return;
}
int key = stack[len];
len--;
add(key, -1);
printf("%d\n", key);
}
int binsearch(int s)
{
int l = 0, r = MAX - 1;
int mid;
while(l <= r)
{
mid = ((l + r) / 2);
int k = sum(mid);
if(s <= k)
{
r = mid - 1;
}
else{
l = mid + 1;
}
}
return l;
}
void mid()
{
if(len == -1)
{
printf("Invalid\n");
return;
}
printf("%d\n", binsearch((len + 2) / 2));
}
int main()
{
scanf("%d", &N);
init();
while(N--)
{
char cmd[16];
scanf("%s", cmd);
switch(cmd[1])
{
case 'u':push();break;
case 'o':pop();break;
case 'e':mid();break;
}
} return 0;
}

最后补一句

其实这是改良过的代码,原来使用STL中的stack作为存储的容器,然后使用cin读取,好几个点没过去,后来换了自己写的stack,然后改成scanf和printf以后就过去了,看来cin和scanf速度差别还是挺大的,STL也要慎用

PAT 1057的更多相关文章

  1. PAT 1057&period; Stack &lpar;30&rpar;

    题目地址:http://pat.zju.edu.cn/contests/pat-a-practise/1057 用树状数组和二分搜索解决,对于这种对时间复杂度要求高的题目,用C的输入输出显然更好 #i ...

  2. PAT 1057 数零壹 (20)(代码&plus;思路)

    1057 数零壹(20 分) 给定一串长度不超过 10​5​​ 的字符串,本题要求你将其中所有英文字母的序号(字母 a-z 对应序号 1-26,不分大小写)相加,得到整数 N,然后再分析一下 N 的二 ...

  3. PAT——1057&period; 数零壹

    给定一串长度不超过105的字符串,本题要求你将其中所有英文字母的序号(字母a-z对应序号1-26,不分大小写)相加,得到整数N,然后再分析一下N的二进制表示中有多少0.多少1.例如给定字符串“PAT ...

  4. PAT 1057 数零壹

    https://pintia.cn/problem-sets/994805260223102976/problems/994805270914383872 给定一串长度不超过 10​5​​ 的字符串, ...

  5. PAT 1057 Stack &lbrack;难&rsqb;&lbrack;树状数组&rsqb;

    1057 Stack (30)(30 分) Stack is one of the most fundamental data structures, which is based on the pr ...

  6. PAT 1057&period; 数零壹&lpar;20&rpar;

    给定一串长度不超过105的字符串,本题要求你将其中所有英文字母的序号(字母a-z对应序号1-26,不分大小写)相加,得到整数N,然后再分析一下N的二进制表示中有多少0.多少1.例如给定字符串“PAT ...

  7. PAT 1057&period; Stack

    Stack is one of the most fundamental data structures, which is based on the principle of Last In Fir ...

  8. PAT甲级1057&period; Stack

    PAT甲级1057. Stack 题意: 堆栈是最基础的数据结构之一,它基于"先进先出"(LIFO)的原理.基本操作包括Push(将元素插入顶部位置)和Pop(删除顶部元素).现在 ...

  9. PAT Basic 1057

    1057 数零壹 给定一串长度不超过 10​5​​ 的字符串,本题要求你将其中所有英文字母的序号(字母 a-z 对应序号 1-26,不分大小写)相加,得到整数 N,然后再分析一下 N 的二进制表示中有 ...

随机推荐

  1. Leetcode House Robber II

    本题和House Robber差不多,分成两种情况来解决.第一家是不是偷了,如果偷了,那么最后一家肯定不能偷. class Solution(object): def rob(self, nums): ...

  2. &lbrack;SAP ABAP开发技术总结&rsqb;业务对象和BAPI

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  3. object 插入元素,插入HTML页面

    object标签用于定义一个嵌入的对象,包括:图像.音频.Java applets.ActiveX.PDF以及Flash.该标签允许您规定插入HTML文档中的对象的数据和参数,以及可用来显示和操作数据 ...

  4. 最简单的ajax调用webservice

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestHelloWorld ...

  5. Spring-MVC请求参数值和向页面传值

    读取请求参数值 方式一:通过HttpServletRequest req做参数 DispatcherServlet在调用处理的方法之前,利用Java反射分析方法的结构,通过分析,将req对象传过来 方 ...

  6. 从零开始学习前端开发 — 15、CSS3过渡、动画

    一.css3过渡 语法: transition: 过渡属性 过渡时间 延迟时间 过渡方式; 1.过渡属性(transition-property) 取值:all 所有发生变化的css属性都添加过渡 e ...

  7. SQLSERVER存储过程语法详解

    CREATE PROC [ EDURE ] procedure_name [ ; number ] [ { @parameter data_type } [ VARYING ] [ = default ...

  8. Android动画-View动画

    View动画 Android动画分为三类:View动画,帧动画,和属性动画.帧动画也是View动画的一种. View动画的作用对象是View,之所以强调这一点是因为其作用对象有别于Android的另一 ...

  9. 免费api

    聚合数据提供30大类,100种以上基础数据API服务,国内最大的基础数据API服务,下面就罗列一些免费的各类API接口. 聚合的免费API接口数据: 手机号码归属地API接口:https://www. ...

  10. day47

    高级布局 一.文档流(normal flow) 1.概念 本质为normal flow(普通流.常规流)将窗体自上而下分成一行一行,块级元素从上至下.行内元素在每行中从左至右的顺序依次排放元素. v_ ...