题目来源
注意点
- pop要输出值
题目描述
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.
输入描述:
Each input file contains one test case. For each case, the first line contains a positive integer N (<= 10 5 10^5 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.
输出描述:
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.
输入例子:
17
Pop
PeekMedian
Push 3
PeekMedian
Push 2
PeekMedian
Push 1
PeekMedian
Pop
Pop
Push 5
Push 4
PeekMedian
Pop
Pop
Pop
Pop
输出例子:
Invalid
Invalid
3
2
2
1
2
4
4
5
3
Invalid
思路简介
就是平衡搜索数 AVL 的模板
查找中位数即查找第 k 小
后续我会补上AVL的模板详解
遇到的问题
无,写完平衡树一遍过
代码
cpp
/**
* https://www.nowcoder.com/pat/5/problem/4110
* multiset
*/
#include<bits/stdc++.h>
using namespace std;
// AVL 树节点结构
struct Node {
int val; // 节点值
int h = 1; // 子树高度(叶子节点高度为1)
int sz = 1; // 子树节点总数(包括自身)
Node *l = nullptr; // 左孩子
Node *r = nullptr; // 右孩子
Node(int v) : val(v) {}
};
// 获取节点高度(空节点高度为0)
int h(Node* x) { return x ? x->h : 0; }
// 获取子树大小(空节点大小为0)
int sz(Node* x) { return x ? x->sz : 0; }
// 更新节点的高度和大小(必须在其孩子更新后调用)
void upd(Node* x) {
if (!x) return;
x->h = 1 + max(h(x->l), h(x->r)); // 高度 = 1 + 左右子树较大高度
x->sz = 1 + sz(x->l) + sz(x->r); // 大小 = 自身 + 左子树大小 + 右子树大小
}
// 右旋:将 y 的左孩子 x 提上来
Node* rotR(Node* y) {
Node* x = y->l;
y->l = x->r; // x 的右子树变成 y 的左子树
x->r = y; // y 成为 x 的右孩子
upd(y); // 先更新 y(现在在下方)
upd(x); // 再更新 x(新的根)
return x;
}
// 左旋
Node* rotL(Node* x) {
Node* y = x->r;
x->r = y->l; // y 的左子树变成 x 的右子树
y->l = x; // x 成为 y 的左孩子
upd(x);
upd(y);
return y;
}
// 计算平衡因子)
int bf(Node* x) { return h(x->l) - h(x->r); }
// 平衡操作
Node* bal(Node* x) {
if (bf(x) > 1) { // 左子树过高
if (bf(x->l) < 0) // LR 型:先左旋左孩子
x->l = rotL(x->l);
return rotR(x); // LL 或 LR 最后都右旋
}
if (bf(x) < -1) { // 右子树过高
if (bf(x->r) > 0) // RL 型:先右旋右孩子
x->r = rotR(x->r);
return rotL(x); // RR 或 RL 最后都左旋
}
return x; // 平衡,无需旋转
}
// 插入值为 v 的节点
Node* ins(Node* x, int v) {
if (!x) return new Node(v); // 空位,创建新节点
if (v < x->val) // 小于当前值则递归左子树
x->l = ins(x->l, v);
else // 大于等于则递归右子树(支持重复元素放右边)
x->r = ins(x->r, v);
upd(x); // 更新高度和大小
return bal(x); // 回溯时平衡
}
// 找子树最小节点(中序后继)
Node* minN(Node* x) {
while (x->l) x = x->l;
return x;
}
// 删除值为 v 的节点(递归)
Node* del(Node* x, int v) {
if (!x) return nullptr;
if (v < x->val)
x->l = del(x->l, v);
else if (v > x->val)
x->r = del(x->r, v);
else { // 找到要删除的节点
if (!x->l || !x->r) { // 只有一个孩子或没有孩子
Node* t = x->l ? x->l : x->r;
delete x;
return t;
}
// 有两个孩子:用后继节点值替换,再递归删除后继
Node* s = minN(x->r);
x->val = s->val;
x->r = del(x->r, s->val);
}
upd(x);
return bal(x);
}
// 查询第 k 小的元素(k 从 1 开始)
int kth(Node* x, int k) {
int ls = sz(x->l); // 左子树大小
if (k <= ls) // 在左子树中
return kth(x->l, k);
if (k == ls + 1) // 就是当前根
return x->val;
return kth(x->r, k - ls - 1); // 在右子树中
}
// 计算中位数
int median(Node* root) {
int n = sz(root);
if (n == 0) return 0; // 可自行处理空树情况
if (n % 2 == 1) // 奇数个
return kth(root, (n + 1) / 2);
// 偶数个:取中间两个数的平均值
return kth(root, n / 2);
}
void solve(){
int n;cin>>n;
stack<int>s;
Node* root = nullptr;
for(int i=0;i<n;++i){
string op;
cin>>op;
if(op=="Push"){
int n;
cin>>n;
root=ins(root,n);
s.push(n);
}
if(op=="Pop"){
if(!s.size()){
cout<<"Invalid\n";
continue;
}
int v=s.top();
s.pop();
root=del(root,v);
cout<<v<<'\n';
}
if(op=="PeekMedian"){
if(!s.size()){
cout<<"Invalid\n";
continue;
}
cout<<median(root)<<'\n';
}
}
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
//fstream in("in.txt",ios::in);cin.rdbuf(in.rdbuf());
int T=1;
//cin>>T;
while(T--){
solve();
}
return 0;
}