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
题目大意:模拟栈,实现相应功能
1.Push:将指定元素压入栈
2.Pop:如果栈不为空,将栈顶元素输出并弹出,如果栈为空,就输出
Invalid
3.PeekMedian:如果栈为空,就输出Invalid,如果栈不为空,设栈中总元素的个数为N,如果N为偶数,就输出栈中第N/2大的元素,如果N为奇数,就输出栈中第(N+1)/2大的元素
思路:Push操作和Pop操作很简单,下面讲讲PeekMedian操作
1.维护一个map,key为栈中元素,value为该元素的个数,定义一个迭代器mid,指向
PeekMedian要输出元素的位置,beforemid为比mid指向元素小的元素总个数,Push或者Pop操作都有可能改变mid和beforemid的参数,但由于每次Push或者Pop操作都只会增加或者减少一位数,因此mid的移动也是常数级的(mid每次最多移动一个单位长度),根据beforemid的变化和栈的中间位置的元素下标mid_pos就可以判断mid的移动方向,此方法可行。
2.mid移动方向判断:若beforemid >= midpos,mid左移,即mid--,同时更新beforemid的值:beforemid -= mid->second;若beforemid + mid->second < midpos,先更新beforemid的值:beforemid += mid->second,再右移mid,即mid++,其他情况mid不移动。
3.当指令为PeekMedian时,这样只需要输出mid->first的值即可
AC代码
#include <iostream>
#include <stack>
#include <map>
using namespace std;
map<int, int> m; // key为栈中元素,value为该元素个数
stack<int> s;
map<int, int> :: iterator mid; // mid始终指向中间元素位置
int beforemid; // 为小于mid指向元素的个数总和
void adjustmid() {
// midpos为栈的中间位置
// 无论栈元素个数总和是奇数还是偶数,均满足下面表达式
int midpos = (s.size() + 1) / 2;
if (beforemid >= midpos) { // 此情况mid左移
mid--;
beforemid -= mid->second; // 更新beforemid的值
} else if (beforemid + mid->second < midpos) { // 此情况mid右移
beforemid += mid->second; // 更新beforemid的值
mid++;
}
}
int main() {
int n;
cin >> n;
while (n--) {
string command;
cin >> command;
if (command == "Push") {
int temp;
cin >> temp;
m[temp]++;
s.push(temp);
if (s.size() == 1) { // 对map相关进行初始化
beforemid = 0;
mid = m.begin();
} else {
if (temp < mid->first) {
beforemid++; // 更新beforemid
}
}
adjustmid(); //调整mid
}
else if (command == "Pop") {
if (s.empty()) {
cout << "Invalid" << endl;
} else {
int temp = s.top();
cout << temp << endl;
s.pop();
m[temp]--;
if (temp < mid->first) { // 更新beforemid
beforemid--;
}
adjustmid(); //调整mid
if (m[temp] == 0) {
m.erase(temp);
}
}
} else if (command == "PeekMedian") {
if (s.empty()) {
cout << "Invalid" << endl;
} else {
cout << mid->first << endl; //输出mid指向的元素
}
}
}
return 0;
}
更多PAT甲级题目:请访问PAT甲级刷题之路--题目索引+知识点分析(正在进行),感谢支持!