單調佇列 滑動視窗

2021-10-03 08:23:39 字數 1478 閱讀 1358

p1886 滑動視窗 /【模板】單調佇列

有乙個長為 n 的序列 a,以及乙個大小為 k 的視窗。現在這個從左邊開始向右滑動,每次滑動乙個單位,求出每次滑動後視窗中的最大值和最小值。

如果按照暴力方法做的話,每一次判斷相鄰的k個數的最大值和最小值,複雜度為o(n*k),肯定會超時,因此就想到把每次的最大值和最小值記錄下來。

先考慮最小值,每次視窗移動的時候,最小值可能會改變,改變的原因有兩個,乙個是遇到比原來最小值更小的數,乙個是原來的最小值不在視窗之內了。因此如果單純記錄最小值的話,如果原來的最小值不在視窗之內的話,原來的記錄就無效了。就想到記錄最小值和次小值,有一種情況,如果次小值離開了視窗,那上**找次小值的取代值呢?記錄第三小的值嗎?**是個頭呢?

因此記錄的話肯定不是記錄最小值,次小值這麼簡單,那麼記錄那些數呢?我們考慮不清楚記錄哪些數,我們可以考慮一下不記錄哪數。當視窗移動的時候,移動前視窗中數字如果比新加入的數字還要大或者相等的話,那他肯定就沒有記錄的必要了,因為我們要的是最小值,越靠右的數字還小,那麼這個數字肯定是優先成為這個最小值的。

因此就想到了單調佇列。怎麼維護這個單調佇列呢?

問的問題是每次滑動視窗時後的最小值和最大值,因此輸出的答案應該有n-k+1個,也就需要迴圈n-k+1次,維護單調遞增的佇列,每次的最小值就是這個佇列的隊首。對於每次視窗移動,一方面首先要把佇列中大於等於新值的數從隊尾出隊,然後判斷隊首的數字有沒有出去。

單調佇列有兩個性質

佇列中的元素其對應在原來的列表中的順序必須是單調遞增的。

佇列中元素的大小必須是單調遞*(增/減/甚至是自定義也可以)

因為單調佇列越靠右的數字肯定是後進佇列的數字,因此判斷隊首的數字就ok了。

1.輸入問題

2.單調佇列的維護:

①迴圈幾次

②頭和尾

③隊尾元素出佇列

④入佇列

⑤隊首元素出佇列

⑥輸出答案

#include

using

namespace std;

#define ll long long

const

int maxn=

1e6+

10;

ll n,k;

ll a[maxn]

;ll p[maxn]

,q[maxn]

;//p儲存數字,q儲存數字的下標

intmain()

//求最小值

ll head=

1,tail=0;

//head對應隊首元素,tail對應隊尾元素

for(ll i=

1;i<=n;i++

) cout

head=

1;tail=0;

for(ll i=

1;i<=n;i++

)return0;

}

單調佇列 滑動視窗

nkoj 2152 description 給你乙個長度為n n 10 6 的陣列,乙個長為k的滑動的窗體從最左移至最右端,你只能見到視窗的k個數,每次窗體向右移動一位,找出窗體所包含的數字的最大和最小值,如下表所示 k的值為3 視窗位置 最小值 最大值 1 3 1 3 5 3 6 7 1 3 1 ...

滑動視窗 單調佇列

給定乙個大小為n 106的陣列。有乙個大小為k的滑動視窗,它從陣列的最左邊移動到最右邊。您只能在視窗中看到k個數字。每次滑動視窗向右移動乙個位置。以下是乙個例子 該陣列為 1 3 1 3 5 3 6 7 k為3。視窗位置 最小值 最大值 1 3 1 3 5 3 6 7 1 3 1 3 1 3 5 3...

滑動視窗 單調佇列

單調佇列與普通佇列不一樣的地方就在於單調佇列既可以從隊首出隊,也可以從隊尾出隊。那麼我們應該怎樣實現單調佇列呢?就拿樣例來談談,設以最小的為標準。8 3 1 3 1 3 5 3 6 7 下文中我們用q來表示單調佇列,p來表示其所對應的在原列表裡的序號。1.由於此時隊中沒有乙個元素,我們直接令1進隊。...