窗口滑动

Given a sequence of data (it may have duplicates), a fixed-sized moving window, move the

window at each iteration from the start of the data sequence, such that

(1) the oldest data element is removed from the window and a new data element is pushed

into the window

(2) find the min&max of the data inside the window at each moving.

(以求窗口最大值为例,求最小值思想与最大值相同)

 常规解法:对于每个窗口计算最大值,时间复杂度O(N*K) (N是序列长度,K是窗口大小)

优先队列:(假设数组为a[N])

窗口中的元素a[i],对于当前窗口的任意i<j的元素,如果a[i]<=a[j],由于a[i]在a[j]之前移出窗口,那么后续包含a[i]的窗口中不可能最大值为a[i],所以a[i]便没有意义。可以构造一个单调递减队列Queue,Queue中每个元素都在当前窗口,窗口移动时:

1)对于移入的元素,插入到Queue中的相应位置k,Queue[k]之前的元素都大于Queue[k],之后的元素都小于Queue[k],并且对于队列中k‘>k的元素,将在Queue[k]移出之前移出,并且Queue[k]>=Queue[k'],所以后续的包含Queue[k']的窗口中最大值不可能为Queue[k'],故可以将k之后的元素删除

2)对于移出的元素,如果Queue[front]元素的位置等于该移出窗口的元素位置,那么该元素需要从Queue中弹出(Queue中不仅要记录元素的值还要记录元素的位置)

//优先队列中元素
struct QueryElement
{
	int value;
	int pos;
};
void WindowMinMax(const int* pData, int Len, int K){
	assert(pData!=NULL && Len>=K);
	QueryElement** maxQuery = new QueryElement*[K+1];	//单调递减队列
	int maxQFront=0, maxQTail=0;	//循环队列,当front==tail时队列空,当(front+1)%Len==tail时队列满
	QueryElement** minQuery = new QueryElement*[K+1];	//单调递增队列
	int minQFront=0, minQTail=0;
	for (int index=0; index<Len; index++){
		int data = pData[index];
		int popDataIndex = index-K;	//当窗口满了之后,滑动窗口时有元素弹出
		//根据弹出窗口的元素,更新队列
		if (popDataIndex>=0){
			if (maxQuery[maxQFront]->pos == popDataIndex){
				delete maxQuery[maxQFront];
				maxQuery[maxQFront] = NULL;
				maxQFront = (maxQFront+1)%(K+1);
			}
			if (minQuery[minQFront]->pos == popDataIndex){
				delete minQuery[minQFront];
				minQuery[minQFront] = NULL;
				minQFront = (minQFront+1)%(K+1);
			}
		}
		//新加入到窗口的元素,插入到max和min队列中
		int qIndex;
		for (qIndex=maxQTail; qIndex!=maxQFront && maxQuery[(qIndex+K)%(K+1)]->value<=data; qIndex = (qIndex+K)%(K+1))
			;
		maxQuery[qIndex] = new QueryElement;
		maxQuery[qIndex]->value = data;	maxQuery[qIndex]->pos = index;
		maxQTail = (qIndex+1)%(K+1);
		for (qIndex=minQTail; qIndex!=minQFront && minQuery[(qIndex+K)%(K+1)]->value>=data; qIndex = (qIndex+K)%(K+1))
			;
		minQuery[qIndex] = new QueryElement;
		minQuery[qIndex]->value = data;	minQuery[qIndex]->pos = index;
		minQTail = (qIndex+1)%(K+1);
		if (index+1>=K){
			cout<<"max="<<maxQuery[maxQFront]->value<<", min="<<minQuery[minQFront]->value<<endl;
		}
	}
	for (int index = maxQFront; index!=maxQTail; index = (index+1)%(K+1)){
		delete maxQuery[index];
		maxQuery[index] = NULL;
	}
	for (int index = minQFront; index!=minQTail; index = (index+1)%(K+1)){
		delete minQuery[index];
		minQuery[index] = NULL;
	}
	delete[] maxQuery;
	delete[] minQuery;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值