#include <string.h>
#include <stdio.h>
#define HEAP_SIZE 30010
template <typename T>
class Less {
public:
char operator()(const T & p1, const T & p2) const {
return p1 < p2;
}
};
template <typename T>
class More {
public:
char operator()(const T & p1, const T & p2) const {
return p1 > p2;
}
};
template <typename T, class C>
class heap {
private:
T mArray[HEAP_SIZE];
C mCmp;
int mHeapLength;
int getLeftChildPos(int pos) {
return pos*2 + 1;
}
int getRightChildPos(int pos) {
return pos*2 + 2;
}
int getParentPos(int pos) {
return (pos-1)/2;
}
void adjustHeapAfterPush() {
int currentPos = mHeapLength - 1;
int parentPos = getParentPos(currentPos);
// printf("%d %d\n", currentPos, parentPos);
while(1) {
if (currentPos == 0) {
break;
}
if (mCmp(mArray[currentPos], mArray[parentPos])) {
T tmp = mArray[currentPos];
mArray[currentPos] = mArray[parentPos];
mArray[parentPos] = tmp;
currentPos = parentPos;
parentPos = getParentPos(currentPos);
} else {
break;
}
}
}
public:
void heapify(int Pos) {
int leftChildPos = getLeftChildPos(Pos);
int rightChildPos = getRightChildPos(Pos);
int max = Pos;
if (rightChildPos + 1 <= mHeapLength) {
max = mCmp(mArray[rightChildPos], mArray[Pos]) ? rightChildPos : Pos;
}
if (leftChildPos + 1 <= mHeapLength) {
max = mCmp(mArray[leftChildPos], mArray[max]) ? leftChildPos : max;
}
if (max == Pos) {
return;
} else {
T tmp = mArray[Pos];
mArray[Pos] = mArray[max];
mArray[max] = tmp;
heapify(max);
}
}
void reset() {
mHeapLength = 0;
memset(mArray, 0, sizeof(mArray));
}
heap(C cmp): mCmp(cmp), mHeapLength(0) {
memset(mArray, 0, sizeof(mArray));
}
void push(T p1) {
mArray[mHeapLength++] = p1;
adjustHeapAfterPush();
}
T top() {
if (mHeapLength) {
return mArray[0];
}
return mArray[0];
}
void pop() {
mArray[0] = mArray[--mHeapLength];
heapify(0);
}
int size() {
return mHeapLength;
}
void printArray() {
printf("Array ");
for (int i = 0; i < mHeapLength; i++) {
printf("%ld ", mArray[i]);
}
printf("\n");
}
void setTop(T p1) {
mArray[0] = p1;
heapify(0);
}
};
Less<long> lessCmp;
More<long> moreCmp;
heap<long, Less<long> > heapLess(lessCmp);
heap<long, More<long> > heapMore(moreCmp);
long MArray[HEAP_SIZE];
long NArray[HEAP_SIZE];
void test() {
Less<long> lessCmp;
More<long> moreCmp;
heap<long, Less<long> > heap1(lessCmp);
heap<long, More<long> > heap2(moreCmp);
heapLess.push(3);
// printf("%ld\n", heap1.top());
heapLess.push(1);
// printf("%ld\n", heap1.top());
heapLess.push(-4);
// printf("%ld\n", heap1.top());
heapLess.push(2);
// heap1.printArray();
// printf("%ld\n", heap1.top());
heapLess.push(8);
// heap1.printArray();
// printf("%ld\n", heap1.top());
// heapLess.push(-1000);
// // printf("%ld\n", heap1.top());
// heapLess.push(190);
// // printf("%ld\n", heap1.top());
// heapLess.push(-3);
// // printf("%ld\n", heap1.top());
// heapLess.setTop(-199);
heapLess.printArray();
heapMore.push(100);
heapMore.push(1);
heapMore.push(98);
heapMore.push(12);
heapMore.push(43);
heapMore.push(56);
heapMore.push(190);
heapMore.push(-3);
printf("LESS\n");
while(heapLess.size()) {
printf("%ld\n", heapLess.top());
heapLess.pop();
}
printf("MORE\n");
while(heapMore.size()) {
printf("%ld\n", heapMore.top());
heapMore.pop();
}
}
void printRes(int M, int N) {
int i = 0;
int Mbegin = 0;
for (int i = 0; i < N; i++) {
if (Mbegin < NArray[i]) {
for(int j = Mbegin; j < NArray[i]; j++) {
// printf("FOR %d %ld\n", Mbegin, NArray[i]);
if (heapMore.size() >= i+1) {
// printf("1 %d %d\n", heapMore.size(), i);
if (heapMore.top() > MArray[j]) {
heapLess.push(heapMore.top());
heapMore.setTop(MArray[j]);
} else {
heapLess.push(MArray[j]);
}
} else {
if (!heapMore.size()) {
// printf("1 heapMore.push %ld\n", MArray[j]);
heapMore.push(MArray[j]);
} else if (heapLess.size() && heapLess.top() < MArray[j]) {
// printf("2 heapMore.push %ld\n", MArray[j]);
heapMore.push(heapLess.top());
heapLess.setTop(MArray[j]);
} else {
// printf("3 heapMore.push %ld i %d size %d\n", MArray[j], i, heapMore.size());
heapMore.push(MArray[j]);
}
}
}
Mbegin = NArray[i];
} else {
heapMore.push(heapLess.top());
heapLess.pop();
}
// heapLess.printArray();
// heapMore.printArray();
printf("%ld\n", heapMore.top());
}
}
int main() {
// test();
heapLess.reset();
heapMore.reset();
memset(MArray, 0, sizeof(MArray));
memset(NArray, 0, sizeof(NArray));
int M;
int N;
scanf("%d %d", &M, &N);
for (int i = 0; i < M; i++) {
scanf("%ld", MArray + i);
}
for (int i = 0; i < N; i++) {
scanf("%ld", NArray + i);
}
printRes(M, N);
}
G++ 832K 313MS.
本质是一个求第k大的问题,之前也遇到过,当时用了算导上的逐步逼近法解的。
这次题目特殊,要求在数组的不断扩展中求第1,2... N大的数,显然,每次扩展完直接排序或者逐步逼近求出第k大铁定要TLE的。
后来看了提示,才知道可以用一个大顶堆和一个小顶堆解决,这个解法要牢记,其实单独的求第k大的数,有一个大顶/小顶堆就足够了,比如要求第k大的数,
那么就搞一个从容量为k的大顶堆,然后顺序往里满塞数组元素,当大顶堆被塞满时,再进入的元素就和大顶堆的堆顶元素(堆中最大)进行比较,如果比堆顶还大,直接pass, 如果比堆顶小,那么替换堆顶为此新元素,然后调整堆,这样最后遍历完元素以后,大顶堆的堆顶就是数组的第k大元素(当然,数组本身必须有>=k个元素)。
堆在有些大数据处理题里面用的也挺多,堆在这里的运用本质类似于筛子,不过这个筛子是固定容量,并且筛选标准不断的在紧缩。
这道题用两个堆的原因是因为该题是不断在顺序的求第1,2,3...k大元素,而每个求第k大的过程中,数组元素可能会有增加,如果只用一个堆,每次重新开始求数组的第k大,
显然效率低,没有充分利用之前的信息。
所以需要两个堆(maxheap minheap),在已经加入了N个元素时(第N步),在第i次GET第i大数组元素时,大顶堆(因为题目要求是求第i “大” 的,因此用大顶)负责保存数组前i大个元素,堆顶就是第i大的元素,而另一个堆,小顶堆则负责存储剩余的第i+1~N个元素,堆顶为这一堆元素中最小的元素(小顶)。
然后再假设第i+1次GET是在加入了M个元素之后(第M步),那么,在这M个元素的添加过程中,首先为了能在第i+1步的时候直接从maxheap的堆顶直接拿到,那么在每次的添加元素时,要做以下的处理:
case1: maxheap的元素个数不到 i +1, 没有填满,那么就拿新元素new和minheap的堆顶进行比较,如果new比minheap堆顶还小,那么必然new小于minheap的每个元素,
而maxheap则需要添加一个new与minheap元素群中的最小元素(不然就不满足第i+1大了,因为minheap有比其还小的),那么就将此元素直接加到maxheap里,并且要调整堆(new不保证比maxheap每个都小)。
case2: 同case1, 但是new比minheap堆顶大,那么将minheap堆顶加入到maxheap,而将new再加入maxheap。
case3:maxheap的元素已经填满了,new比maxheap的堆顶要小,将maxheap堆顶去掉,加到minheap中,将new加入maxheap。
case4:同case3,但是new>=堆顶, 那么直接加入minheap。
特殊case1:,在一个ADD之后,紧接来了几次GET, 这种情况下,不会有新元素加入,要进行的操作就是不断的把minheap的堆顶挪到maxheap中,maxheap堆顶就是要求第k大.
特殊case2: 在将new与min/maxheap堆顶比较时, 要考虑minheap和maxheap为空的情况。
这道题在知道解法以后也不是很好写,再次感受到了自己在行动和思维上的差距,自己写的堆又在求parentPos的时候多了-1,而后面在一条条的ADD GET指令的交叉执行中,
又是险象环生。不过也有了些开悟,纵观自己coding这些年,涉及到比较复杂的逻辑,有一点是我做的很差的,及为每个变量和函数赋予决定精确和合适的含义(不是指命名),在写code时,经常对某个变量的真正作用与定位认识糢糊,最普遍的就是+/-1的问题,就是因为定位不准. 这是一个痛点,以前会绕开,以目的为导向,不过这次一定要下决心解决这个痛点,bypass最终败给勇往直前.