队列-单调队列

153 阅读1分钟

单调队列

经典类型:找出滑动窗口中的最大值/最小值

如果采用数组模拟队列

int hh = 0, tt = -1;
for (int i = 0; i < n; i ++) {
    while (hh <= tt && check_out(q[hh])) hh ++ ;  // 判断队头是否滑出窗口
    while (hh <= tt && check(q[tt], i)) tt -- ;
    q[ ++ tt] = i;
}

直接采用STL的std::deque()

for (int i = 0; i < nums.size(); i++) {
    if (!q.empty() && i - q.front() + 1 > k) q.pop_front();
    while(!q.empty() && check(q.back(), i)) q.pop_back();
    q.push_back(i);
}

练习题

在《剑指Offer专项突破版》中有两个练习题

239. 滑动窗口最大值利用单调队列可以做到时间复杂度为O(N),空间复杂度为O(K)

vector<int> maxSlidingWindow(vector<int>& nums, int k) {
    deque<int> q;
    vector<int> ans;
    for (int i = 0; i < nums.size(); i++) {
        if (!q.empty() && i - q.front() + 1 > k) q.pop_front();
        while(!q.empty() && nums[q.back()] <= nums[i]) q.pop_back();
        q.push_back(i);

        if (i >= k-1) ans.push_back(nums[q.front()]);
    }
    return ans;
}

剑指 Offer59-II.队列的最大值也可以用单调队列来实现

class MaxQueue {
public:
    MaxQueue() {}
    
    int max_value() {
        if (nums.empty()) return -1;
        return maxQ.front();
    }
    
    void push_back(int value) {
        nums.push(value);
        while(!maxQ.empty() && maxQ.back() <= nums.back()) maxQ.pop_back();
        maxQ.push_back(nums.back());
    }
    
    int pop_front() {
        if (nums.empty()) return -1;
        int ans = nums.front();
        if (!maxQ.empty() && maxQ.front() == ans) maxQ.pop_front();
        nums.pop();
        return ans;
    }

private:
    deque<int>      maxQ;
    queue<int>      nums;  
};

练习题

参考资料

  • 《剑指Offer专项突破版》