牛客3750题解:滑动窗口最大值的单调队列解法
一、问题理解
牛客3750题要求找出数组中所有大小为k的滑动窗口中的最大值。这是一个经典的算法问题,在数据流处理、时间序列分析等领域有广泛应用。
二、算法核心思想
使用单调递减队列(deque)来维护当前窗口中的候选最大值:
队列头部始终是当前窗口的最大值
队列元素按从大到小排列
通过下标判断移除过期元素
三、完整代码实现(带注释)
class Solution { public: vector<int> maxInWindows(const vector<int>& num, int size) { vector<int> result; // 处理特殊情况:窗口大小为0或大于数组长度 if (size == 0 || size > num.size()) return result; deque<int> dq; // 存储下标,维护单调递减队列 for (int i = 0; i < num.size(); ++i) { // 移除超出窗口范围的元素 while (!dq.empty() && dq.front() <= (int)(i - size)) { dq.pop_front(); } // 维护单调递减性质 while (!dq.empty() && num[dq.back()] <= num[i]) { dq.pop_back(); } dq.push_back(i); // 当窗口形成后开始记录结果 if (i >= (int)(size - 1)) { result.push_back(num[dq.front()]); } } return result; } };
四、关键点解析
单调队列维护:
队列中存储的是元素下标而非值本身
新元素入队时会移除所有比它小的元素
窗口边界处理:
通过比较队首元素下标与i-size判断是否过期
只有当i >= size-1时才记录结果
时间复杂度:
每个元素最多入队出队各一次
总体时间复杂度为O(n)
五、常见问题解答
Q: 为什么使用deque而不是普通队列? A: deque支持两端操作,便于同时处理队首过期元素和队尾维护单调性
Q: 如何处理重复最大值? A: 算法会自动保留最右侧的最大值,保证后续窗口的正确性
Q: 空间复杂度是多少? A: 最坏情况下O(k),当数组单调递减时队列会存储整个窗口元素
原创内容 转载请注明出处