1057 Stack

题目大意

让你在栈的入栈弹栈基础之上在添加一个功能——PeekMedian,选出第k小的元素,规定n为偶数时k = n/2;奇数时为(n+1)/2.

思路解析

一道很硬的题,涉及到高级数据结构树状数组,有关知识点讲解请移步:点击这里

用暴力只能通过一个测试点。声明C数组,大小为100010,下标为值,元素为1表示该值存在;
所以用getsum累加时,x前面有n个1就说明x是第n+1位。另外,在找第k小的数时要用二分法。还要注意不能使用C++的cin输入,在声明max的时候过大会导致PAT编译失败.

2020.5.20更新:
今天复习数据结构忽然回忆到这题,觉得有些不妥。
对于本题利用树状数组未免有些“小题大做”了。本题要找第K小的元素,可以考虑使用快排中的分组思想。
这是因为每一趟快排都会把一个元素pivot放到正确位置,且pivot之前的元素均小于pivot,这也就说明pivot的位置pos就是第pos小的元素。

有小伙伴可能会疑问:这种方法对于有重复元素的情况还适用吗?
是适用的。请看下面的分组代码:
...
while(low < high){
	while(low < high && arr[high] >= pivot) {
		high--;
	}
	arr[low] = arr[high];
	while(low < high && arr[low] <= pivot) {
		low++;
	}
	arr[high] = arr[low];
}
arr[low] = pivot;
...



请看到第2行和第6行while中的判断条件,high指针是将小于pivot的元素放到了pivot之前,所以就算有重复元素也不会记入K;同理,low指针将大于pivot的元素放到pivot的后面。


示例代码

#include<iostream>
#include<stack>
using namespace std;
int n;
int mmax = 100010;
int C[100010];//角标作为值,元素为1表明存在该值
int lowbit(int i) {
	return i&(-i);
}
void update(int x,int v) {
	for (int i = x; i < mmax; 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;
}
int main() {
	scanf("%d", &n);
	char str[15];
	stack<int> sta;
	for (int i = 0; i < n; i++) {
		scanf("%s", str);
		if (str[1] == 'e') {//PeekMedian
			if (sta.empty()) {
				printf("Invalid\n");
				continue;
			}
			int left = 1, right = mmax, k = (sta.size() + 1) / 2;
			while (left < right) {
				int mid = (left + right) / 2;
				if (getsum(mid) >= k) {
					right = mid;
				}
				else {
					left = mid + 1;
				}
			}
			printf("%d\n", left);
		}
		else if (str[1] == 'u') {//push
			int temp;
			scanf("%d", &temp);
			sta.push(temp);
			update(temp, 1);
		}
		else {//pop
			if (sta.empty()) {
				printf("Invalid\n");
				continue;
			}
			printf("%d\n", sta.top());
			update(sta.top(), -1);//要将该位置为0,所以减去前面加的1
			sta.pop();
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值