題目描述
給定乙個陣列a,有乙個大小為w的滑動視窗,該滑動視窗從最左邊滑到最後邊。在該視窗中你只能看到w個數字,每次只能移動乙個位置。我們的目的是找到每個視窗w個數字中的最大值,並將這些最大值儲存在陣列b中。
例如陣列a=[1 3 -1 -3 5 3 6 7], 視窗大小w為3。則視窗滑動過程如下所示:
window position max
————— —–
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
輸入引數為陣列a和w大小
輸出為陣列b,其中b[i]儲存了a[i]到a[i+w-1]中w個數字的最大值。
一、簡單的解法
乙個最簡單的想法就是每次移動都計算w個數字的最大值並儲存起來,每次計算w個數字的最大值需要o(w)的時間,而滑動過程需要滑動n-w+1次,n為陣列大小,因此總共的時間為o(nw)。**如下:
/*最大滑動視窗主函式*/
void maxslidingwindow(int a, int n, int w, int b)
/*求陣列最大值*/
intmax(int a, int n)
} return
max;
}
二、最大堆解法
第1個方法思路簡單,但是時間複雜度過高,因此需要改進。可以使用乙個最大堆來儲存w個數字,每次插入數字時只需要o(lgw)的時間,從堆中取最大值只需要o(1)的時間。隨著視窗由左向右滑動,因此堆中有些數字會失效(因為它們不再包含在視窗中)。
typedef pair pair;
void maxslidingwindow(int a, int n, int w, int b)
q.push(pair(a[i], i));
} b[n-w] = q.top().first;
}
如果陣列本身有序,則裡面的while迴圈不會執行,堆大小會增大到n。因為堆大小並不保持在w不變,因此該演算法時間複雜度為o(nlgn)。
三、雙向佇列o(n)解法
最大堆解法在堆中儲存有冗餘的元素,比如原來堆中元素為[10 5 3],新的元素為11,則此時堆中會儲存有[11 5 3]。其實此時我們可以清空整個佇列,然後再將11加入到佇列即可,即只在佇列中保持[11]。使用雙向佇列可以滿足要求,滑動視窗的最大值總是儲存在佇列首部,佇列裡面的資料總是從大到小排列。當遇到比當前滑動視窗最大值更大的值時,則將佇列清空,並將新的最大值插入到佇列中。如果遇到的值比當前最大值小,則直接插入到佇列尾部。每次移動的時候需要判斷當前的最大值是否在有效範圍,如果不在,則需要將其從佇列中刪除。由於每個元素最多進隊和出隊各一次,因此該演算法時間複雜度為o(n)。
void maxslidingwindow(int a, int n, int w, int b)
for (int i = w; i < n; i++)
b[n-w] = a[q.front()];
}
最大滑動視窗
給定乙個陣列a,有乙個大小為w的滑動視窗,該滑動視窗從最左邊滑到最後邊。在該視窗中你只能看到w個數字,每次只能移動乙個位置。我們的目的是找到每個視窗w個數字中的最大值,並將這些最大值儲存在陣列b中。例如陣列a 1 3 1 3 5 3 6 7 視窗大小w為3。則視窗滑動過程如下所示 window po...
最大滑動視窗
給定乙個陣列a,有乙個大小為w的滑動視窗,該滑動視窗從最左邊滑到最後邊。在該視窗中你只能看到w個數字,每次只能移動乙個位置。我們的目的是找到每個視窗w個數字中的最大值,並將這些最大值儲存在陣列b中。例如陣列a 1 3 1 3 5 3 6 7 視窗大小w為3。則視窗滑動過程如下所示 window po...
239 最大滑動視窗
滑動視窗當中的最大值 掃瞄正個陣列,o n 每個節點處需要進行掃瞄k個節點,所有時間複雜度為o nk class solution return result private void helper int nums,int start,int end,int result,int i result...