演算法 使用單調佇列解決滑動視窗問題

2021-10-04 10:15:26 字數 2030 閱讀 9164

給定乙個大小為n≤106的陣列。

有乙個大小為k的滑動視窗,它從陣列的最左邊移動到最右邊。

您只能在視窗中看到k個數字。

每次滑動視窗向右移動乙個位置。

以下是乙個例子:

該陣列為[1 3 -1 -3 5 3 6 7]k3

視窗位置

最小值最大值

[1 3 -1] -3 5 3 6 7-13

1 [3 -1 -3] 5 3 6 7-33

1 3 [-1 -3 5] 3 6 7-35

1 3 -1 [-3 5 3] 6 7-35

1 3 -1 -3 [5 3 6] 736

1 3 -1 -3 5 [3 6 7]37

您的任務是確定滑動視窗位於每個位置時,視窗中的最大值和最小值。

輸入格式

輸入包含兩行。

第一行包含兩個整數nk,分別代表陣列長度和滑動視窗的長度。

第二行有n個整數,代表陣列的具體數值。

同行資料之間用空格隔開。

輸出格式

輸出包含兩個。

第一行輸出,從左至右,每個位置滑動視窗中的最小值。

第二行輸出,從左至右,每個位置滑動視窗中的最大值。

輸入樣例:

8 3

1 3 -1 -3 5 3 6 7

輸出樣例:
-1 -3 -3 -3 3 3

3 3 5 5 6 7

​ 通過讀題,我們可以簡單描述為有乙個長度為n的陣列a[n],給定乙個長度為k的「視窗」,a[n]會從頭開始依次經過這個視窗,我們需要求的是陣列從第k - 1個元素開始,也就是視窗第一次被填滿時開始一直到陣列結尾,每一次視窗中的值被更新後的最大值和最小值

​ 不難發現,這個視窗是乙個從尾部進入,頭部出去的模型,那很容易聯想到先入先出的資料結構——佇列,我們可以假設這個視窗就是乙個佇列,每次陣列元素會從隊尾入隊,當視窗被填滿後,當前的隊頭元素要出隊,我們維護這樣乙個長度為k的佇列,每次求出它的最大值和最小值即可

​ 然後即便我們想到使用佇列進行求解,這個問題還是顯得十分複雜,我們怎樣簡化它呢?答案就是使用單調佇列

​ 單調佇列即佇列中的元素滿足單調遞增或遞減的性質,保證隊頭隊尾元素是佇列的最大值或最小值,因為從模擬這道題的過程我們可以得出,假設在求視窗中的最小值時,陣列存在[..., 3, -1, 0, ...]這樣一段序列,當3入隊時,它可能是當前隊中最小的元素,但當視窗再一次向後移動時,-1進入佇列,此時無論如何3都不會再被當成最小值輸出,因為-1一定會在3之後出隊,所以這時3就沒有必要再存在於隊中,我們將它排除,如此迴圈,使得每次入隊的元素一定大於前面的元素,我們就可以得到乙個單調遞增的佇列,此時求最小值,我們直需要返回隊頭元素即可

​ 以上是最小值,求最大值時我們只需要改變元素入隊時的判斷條件,即可改變單調佇列的單調性,使隊頭元素變成最大值,下面是**

#include

using namespace std;

const

int n =

1000010

;int q[n]

, a[n]

;int n, k;

intmain()

puts(""

);hh =

0, tt =-1

;// 最大值

for(

int i =

0; i < n;

++i)

}

​ 這裡我們使用q[n]來表示滑動視窗中陣列元素的下標,這樣更方便我們對佇列進行操作

單調佇列 滑動視窗

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...

單調佇列 滑動視窗

p1886 滑動視窗 模板 單調佇列 有乙個長為 n 的序列 a,以及乙個大小為 k 的視窗。現在這個從左邊開始向右滑動,每次滑動乙個單位,求出每次滑動後視窗中的最大值和最小值。如果按照暴力方法做的話,每一次判斷相鄰的k個數的最大值和最小值,複雜度為o n k 肯定會超時,因此就想到把每次的最大值和...