目录

1,题目描述

题目大意

2,思路

数据结构

函数讲解

1,void update(int x, int v):

2,int getsum(int x):

3,void PeekMedian():

3,解题历程

第一搏:

第二搏:

第三搏

第四搏:

4,代码

第一搏:

AC代码(柳神)


1,题目描述

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

题目大意

给出一系列栈的操作,输出对应操作的标志(入栈:不输出;出栈:输出弹出的值,若栈空,则输出Invalid;PeekMedian:输出当前栈内数据的中位数)

2,思路

这一题的解法主要有两种:分块法树状数组法

这里主要介绍树状数组的解法,不了解树状数组的同学可以参考这些大神的文章:

初步了解树状数组:@半根毛线code【树状数组彻底入门 】;

进一步总结:@和山米兰【树状数组】;

树状数组与本题的关系:@ 没想好呢111 【PAT 甲级 1057 Stack】

若想进一步了解树状数组,可以阅读算法笔记(晴神笔记)第十三章 专题拓展,里面有对树状数组的详细讲解

补充:根据晴神笔记的内容,我也整理出了一篇讲解树状数组的博客,感兴趣的同学可以戳这里:树状数组【算法笔记/晴神笔记】,很详细哟!

数据结构

  • 全局变量int c[maxn]:下标为key(入栈/出栈的值)。c[i]表示在i的辖区范围(lowBit(i))内,小于i的key的个数

函数讲解

1,void update(int x, int v):

当Push x时,辖区范围(lowBit(i))内包括x的全部需要更新(加一。表示对x后面的每个数来说,比它小的元素的数目加一),即update(x, i);当Pop时,正好相反,需要减一,即update(x, -1)。

2,int getsum(int x):

求出当前栈中,所有小于等于x的元素的数目。

比如,当x=7时:ans += (c[7] + c[6] + c[4]);(7,6,4即for(int i = x; i >= 1; i -= lowbit(i))得出的)

c[7]范围内小于等于7的元素数目,加上c[6]范围内小于等于6的元素数目,加上c[4]范围内小于等于4的元素数目.。

3,void PeekMedian():

主体为二分查找。

void PeekMedian() {int left = 1, right = maxn, mid, k = (s.size() + 1) / 2;while(left < right) {mid = (left + right) / 2;if(getsum(mid) >= k)right = mid;elseleft = mid + 1;}printf("%d\n", left);
}

这里没有用if(getsum(mid) == k) break; printf("%d\n",mid),是因为,可能不存在正好 getsum(mid) == k的mid值,所以if(getsum(mid) >= k)时,right = mid;正好可以解决这个问题。

3,解题历程

第一搏:

原先想着,每插入一个就sort一次可能有点浪费。。。(快排时间复杂度平均为O(nlogn)),于时就想着自定义插入删除函数(原本是有序的,只需要删除指定元素即可,类似于数组删除元素(时间复杂度为O(n))。然而有三个测试点超时。。。

vector<int> stack, temp;
void insert1(int key){temp.push_back(key);for(int i = temp.size() - 1; i > 0; i--){if(temp[i] < temp[i-1]){swap(temp[i], temp[i-1]);}else break;}
}
void delete1(int key){int i;for(i = 0; i < temp.size(); i++){if(temp[i] == key) break;}temp.erase(temp.begin() + i);
}

字符串的处理方式

string cmd;
for(int i = 0; i < N; i++){cin>>cmd;

第二搏:

修改了字符串的处理方式:

    char cmd[11];int key, out;for(int i = 0; i < N; i++){scanf("%s", cmd);if(strcmp(cmd, "Pop") == 0){//字符串比较大小

然而还是超时。。。(甚至比cin还要慢一点,,,可能是偶然,因为同一代码几次运行的结果也可能不一样)

第三搏

我仍不死心,于时想用map试一试,key为入栈的元素,value为key出现的次数,每次求中位数时sum从小到大累加value值,若sum>=(stack.size() + 1) / 2) 时,key即为所求。

#include<iostream>
#include<vector>
#include<map>
#include<string.h>
#include<algorithm>
using namespace std;vector<int> stack;
map<int, int> temp;             //利用map自动对key排序的特性
int main(){
#ifdef ONLINE_JUDGE
#elsefreopen("1.txt", "r", stdin);
#endifint N;//操作次数cin>>N;char cmd[11];int key, out;int num = 0, sum = 0;for(int i = 0; i < N; i++){scanf("%s", cmd);if(strcmp(cmd, "Pop") == 0){if(stack.size() == 0){printf("Invalid\n");}else{out = stack[stack.size()-1];printf("%d\n", out);stack.pop_back();temp[out]--;                //out对应的值 出现次数减一}}else if(strcmp(cmd, "PeekMedian") == 0){if(stack.size() == 0){printf("Invalid\n");}else{for(auto it : temp){sum += it.second;if(sum >= (stack.size() + 1) / 2){//寻找中位数printf("%d\n", it.first);break;}}sum = 0;}}else if(strcmp(cmd, "Push") == 0){scanf("%d", &key);stack.push_back(key);temp[key]++;                    //out对应的值 出现次数加一}}return 0;
}

第四搏:

没招了。

大神的做法基本都是树状数组之类的。

仿照柳神的代码敲了一遍。。。(柳神666,太不容易了)

再一次感受到了算法的魅力!!!

4,代码

第一搏:

#include<iostream>
#include<vector>
#include<map>
#include<string.h>
#include<algorithm>
using namespace std;vector<int> stack, temp;
void insert1(int key){temp.push_back(key);for(int i = temp.size() - 1; i > 0; i--){if(temp[i] < temp[i-1]){swap(temp[i], temp[i-1]);}else break;}
}
void delete1(int key){int i;for(i = 0; i < temp.size(); i++){if(temp[i] == key) break;}temp.erase(temp.begin() + i);
}int main(){
#ifdef ONLINE_JUDGE
#elsefreopen("1.txt", "r", stdin);
#endifint N;//操作次数cin>>N;char cmd[11];int key, out;for(int i = 0; i < N; i++){scanf("%s", cmd);if(strcmp(cmd, "Pop") == 0){//字符串比较大小if(stack.size() == 0){printf("Invalid\n");}else{out = stack[stack.size()-1];printf("%d\n", out);stack.pop_back();delete1(out);}}else if(strcmp(cmd, "PeekMedian") == 0){if(stack.size() == 0){printf("Invalid\n");}else{out = temp[(temp.size() + 1) / 2 - 1];printf("%d\n", out);}}else if(strcmp(cmd, "Push") == 0){scanf("%d", &key);stack.push_back(key);insert1(key);}//cout<<"YES"<<endl;}return 0;
}

AC代码(柳神)

#include <iostream>
#include <stack>
#define lowbit(i) ((i) & (-i))
const int maxn = 100010;
using namespace std;
int c[maxn];
stack<int> s;
void update(int x, int v) {for(int i = x; i < maxn; i += lowbit(i))c[i] += v;
}
int getsum(int x) {int sum = 0;for(int i = x; i >= 1; i -= lowbit(i))sum += c[i];return sum;
}
void PeekMedian() {int left = 1, right = maxn, mid, k = (s.size() + 1) / 2;while(left < right) {mid = (left + right) / 2;if(getsum(mid) >= k)right = mid;elseleft = mid + 1;}printf("%d\n", left);
}
int main() {
#ifdef ONLINE_JUDGE
#elsefreopen("1.txt", "r", stdin);
#endifint n, temp;scanf("%d", &n);char str[15];for(int i = 0; i < n; i++) {scanf("%s", str);if(str[1] == 'u') {scanf("%d", &temp);s.push(temp);update(temp, 1);}else if(str[1] == 'o') {if(!s.empty()) {update(s.top(), -1);printf("%d\n", s.top());s.pop();} else {printf("Invalid\n");}}else {if(!s.empty())PeekMedian();elseprintf("Invalid\n");}}return 0;
}

**PAT_甲级_1057 Stack (30分) (C++)【字符串处理/栈的模拟/树状数组】相关推荐

  1. [2020.10.30NOIP模拟赛]字符串水题【SA,树状数组】

    正题 题目大意 一个字符串SSS. 若干个询问,每次询问一个串TTT和l,rl,rl,r.询问有多少个TTT和SSS的公共子串满足和为[l,r][l,r][l,r] 解题思路 考虑枚举子串左端,那么右 ...

  2. PAT甲级1147 Heaps (30 分):[C++题解]堆、树的遍历、dfs、完全二叉树建树

    文章目录 题目分析 题目来源 题目分析 来源:acwing 分析:给定完全二叉树,判断是否是堆,需要区分大根堆,小根堆.后面是输出后序遍历. AC代码 #include<bits/stdc++. ...

  3. 1057 Stack (30 分)【难度: 中 / 知识点: 树状数组 STL】

    https://pintia.cn/problem-sets/994805342720868352/problems/994805417945710592 本题的一个最大的难点,就是如何给一个动态的区 ...

  4. Perform the Combo CodeForces - 1311C(字符串反转+树状数组)

    You want to perform the combo on your opponent in one popular fighting game. The combo is the string ...

  5. CCF201709-5 除法(100分)【树状数组+线段树】

    试题编号: 201709-5 试题名称: 除法 时间限制: 10.0s 内存限制: 256.0MB 问题描述: 问题描述 小葱喜欢除法,所以他给了你N个数a1, a2, ⋯, aN,并且希望你执行M次 ...

  6. [蓝桥杯][算法提高VIP]分苹果(差分||树状数组)

    题目描述 小朋友排成一排,老师给他们分苹果. 小朋友从左到右标号1-N.有M个老师,每次第i个老师会给第Li个到第Ri个,一共Ri-Li+1个小朋友每人发Ci个苹果. 最后老师想知道每个小朋友有多少苹 ...

  7. 【Ynoi2011】成都七中【树论】【点分树】【离线】【树状数组】

    题意:给一棵树,点有颜色,qqq 次询问,每次给定 l,r,xl,r,xl,r,x ,求只保留编号在 [l,r][l,r][l,r] 中的点时点 xxx 所在连通块的颜色数. 所有数 ≤105\leq ...

  8. P5311-[Ynoi2011]成都七中【点分树,树状数组】

    正题 题目链接:https://www.luogu.com.cn/problem/P5311 题目大意 给出nnn个点的一棵树,每个节点有一个颜色,mmm次询问提出区间[l,r][l,r][l,r]的 ...

  9. hdu-2852 KiKi's K-Number---二分+树状数组

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2852 题目大意: 题意:     给出三种操作,     0 在容器中插入一个数.     1 在容 ...

最新文章

  1. centos安装emqtt_benchmark
  2. UA MATH567 高维统计II 随机向量8 图的max-cut问题 0.5近似算法
  3. rhel7搭建可用实验环境
  4. 工作110:地址里面返回参数
  5. 内核网络设备的注册与初始化
  6. 机器学习面试问题大概梳理(转)
  7. Windows核心编程_远线程方式实现Dll注入
  8. 爱了爱了!0.052 秒打开 100GB 数据,这个开源库火爆了!
  9. gcc 混合连接动态库和静态库
  10. 开关电源适配器原理_迅为i.MX6ULL开发板原理图分析介绍
  11. 2021-09-08推荐系统有如下三大类算法
  12. 软件开发技术文档编写规范
  13. iRedMail邮件服务的部署
  14. postgresql 9.5 now()函数少8小时
  15. 不同数据类型混合运算及类型转换
  16. 网页验证码识别实例VB.NET2019(二)
  17. 按住crtl单击MyEclipse的方法没有跳转的解决办法
  18. 使用 vue-i18n 进行Vue国际化处理,使项目切换中英文
  19. 软件工程应用与实践(1)——项目简介和小组分工
  20. FlexRay学习笔记_2

热门文章

  1. @Transactional(propagation)
  2. Promise is a promise
  3. [2016 T-EDGE]王坚对话无人机教父:创新就要享受走在悬崖边的刺激
  4. 「张一鸣」“突袭”「王兴」
  5. 多线程操作同一个变量
  6. 趣味算法 四个点在同一个半圆的概率
  7. win7下搭建小程序服务器,重磅!微信PC端支持小程序直接开启 适配Win7及以上系统...
  8. HTML5 drag和drop的亲手实践
  9. C ++ 程序调用CUDA静态库
  10. AndroidO Notification横幅通知(HangUp Notification)