第一版程式碼:
class Solution {
private:
class MyQueue { //單調佇列(從大到小)
public:
deque<int> que; // 使用deque來實現單調佇列
// 每次彈出的時候,比較當前要彈出的數值是否等於佇列出口元素的數值,如果相等則彈出。
// 同時pop之前判斷佇列當前是否為空。
void pop(int value) {
if (!que.empty() && value == que.front()) {
que.pop_front();
}
}
// 如果push的數值大於入口元素的數值,那麼就將佇列後端的數值彈出,直到push的數值小於等於佇列入口元素的數值為止。
// 這樣就保持了佇列裡的數值是單調從大到小的了。
void push(int value) {
while (!que.empty() && value > que.back()) {
que.pop_back();
}
que.push_back(value);
}
// 查詢當前佇列裡的最大值 直接返回佇列前端也就是front就可以了。
int front() {
return que.front();
}
};
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
MyQueue que;
vector<int> result;
for (int i = 0; i < k; i++) { // 先將前k的元素放進佇列
que.push(nums[i]);
}
result.push_back(que.front()); // result 記錄前k的元素的最大值
for (int i = k; i < nums.size(); i++) {
que.pop(nums[i - k]); // 滑動視窗移除最前面元素
que.push(nums[i]); // 滑動視窗前加入最後面的元素
result.push_back(que.front()); // 記錄對應的最大值
}
return result;
}
};
第二版程式碼如下:
第一個問題:如何實現滑動視窗, 透過單調遞減的單向佇列
第二個問題:這個構建過程,注意規則,裡面只有三個函式 彈出的話如果是遞減,滑動視窗移除的值等於視窗的front的值的話,那麼說明可以彈出,否則不用彈出
如何壓入呢,首先的得排完,需要把要進入視窗的值和佇列中的值進行比較,也就是和佇列中的back比較,假如back小那麼就把back刪瞭然後到最後那麼就形成了遞減的,然後再把它壓入即可
最後的函式就是front函式 返回佇列首值從而確保每次返回的都是最大值。不要把佇列和滑動視窗當成一個東西,佇列是為了維護視窗裡的最大值,每當視窗移動的時候我們要確保佇列的首部是最大值。
class Solution {
private:
class MyQueue { //單調佇列(從大到小)
public:
deque<int> que; // 使用deque來實現單調佇列
// 每次彈出的時候,比較當前要彈出的數值是否等於佇列出口元素的數值,如果相等則彈出。
// 同時pop之前判斷佇列當前是否為空。
void pop(int value) {
if (!que.empty() && value == que.front()) {
que.pop_front();
}
}
// 如果push的數值大於入口元素的數值,那麼就將佇列後端的數值彈出,直到push的數值小於等於佇列入口元素的數值為止。
// 這樣就保持了佇列裡的數值是單調從大到小的了。
void push(int value) {
while (!que.empty() && value > que.back()) {
que.pop_back();
}
que.push_back(value);
}
// 查詢當前佇列裡的最大值 直接返回佇列前端也就是front就可以了。
int front() {
return que.front();
}
};
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
MyQueue que;
vector<int> result;
for (int i = 0; i < k; i++) { // 先將前k的元素放進佇列
que.push(nums[i]);
}
result.push_back(que.front()); // result 記錄前k的元素的最大值
for (int i = k; i < nums.size(); i++) {
que.pop(nums[i - k]); // 滑動視窗移除最前面元素
que.push(nums[i]); // 滑動視窗前加入最後面的元素
result.push_back(que.front()); // 記錄對應的最大值
}
return result;
}
};
重點在這個滑動視窗移動的for迴圈裡,先移除在加入, 然後注意這個單向佇列的設計邏輯,刪除的時候由於我們只關注出口的元素,所以只有當出口的元素等於視窗移除的元素時才執行移除
否則不相等的話是需要進行保留的,因為這個佇列裡面維護的是視窗裡的最大值元素,而當我們進行新增的時候也是要維持這個單調遞減的順序,否則前面的元素都進行刪除即可,同時注意到
這個移除的區別,前面的移除是對佇列的出口元素進行移除,後面的移除是對佇列的入口元素進行移除。然後就是最後的迴圈邏輯,前面已經有了k個元素所以這裡肯定要從k開始。