NC50528 - 滑動窗口(單調隊列)

題目鏈接

思路:在區間滑動的時候,每次會有一個新的數進來和一箇舊的數出去。需要用一個合適的數據結構來更新這樣的狀態。

如果出去的數是當前的最大值或者最小值,要可以很快找到下一個代替的數;

如果進來的數可以成爲新的最大的數或者最小的數,或者都不是那又該怎樣存儲這個數?

單調隊列 ,它來了;

就從找區間最小值來說:一個新的數加入的時候,從隊列的尾部開始比較,如果新加入的數 ≤ 尾部的數, 尾部.pop() ,一直到 新加入的數 > 尾部的數 OR 隊列裏沒一個能打的-> 新加入的數成爲頭部,這樣就可以保證每次進來的數經過更新後這個隊列裏面頭部永遠都是最小的;

當然在上面的操作之前需要先判斷一下 頭部的那些節點是不是過期了,有些數經過區間滑動並不在區間裏面了,所以循環判斷一下,過期了 pop() 掉就好了,所以這麼一搞隊列就空掉了也不是沒有可能。

最大最小分開搞,O(n) 就可以A 遼 skr~

#include <bits/stdc++.h>
using namespace std;

int n, k, a[1000006];
struct node {
	int dig, pos;
} deq[1000006];

int main() {
	scanf("%d %d", &n, &k);
	for(int i = 1;i <= n; i++) {
		scanf("%d", &a[i]);
	}
	
	int head = 1, tail = 0;
	node t;
	for(int i = 1;i <= n; i++) {
		while(head <= tail && deq[head].pos < i-k+1) head++; // 刪除過期的元素
		while(head <= tail && a[i] <= deq[tail].dig) tail--;// 保持單調的遞增性
		t.dig = a[i]; t.pos = i;
		deq[++tail] = t;
		if(i >= k) printf("%d ", deq[head].dig);
	}
	puts("");
	
	head = 1, tail = 0;
	for(int i = 1;i <= n; i++) {
		while(head <= tail && deq[head].pos < i-k+1) head++;
		while(head <= tail && a[i] >= deq[tail].dig) tail--;
		t.dig = a[i]; t.pos = i;
		deq[++tail] = t;
		if(i >= k) printf("%d ", deq[head].dig);
	}
	puts("");
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章