C++怎么实现滑动窗口最大值_C++单调队列教程【算法】

4次阅读

滑动窗口最大值用std::deque维护下标最稳,核心是单调递减下标队列:队首为当前窗口最大值下标,队列存索引而非值;i

C++怎么实现滑动窗口最大值_C++单调队列教程【算法】

滑动窗口最大值用 std::deque 维护下标最稳

直接用 std::priority_queue 或暴力遍历,要么无法及时删除过期元素,要么超时。核心是维护一个「单调递减的下标队列」:队首永远是当前窗口内最大值的下标,队列里存的是数组索引,不是值本身。

  • 每次新元素进来前,从队尾开始弹出所有 nums[deque.back()] 的下标——保证队列严格递减
  • 检查队首下标是否还在窗口内:if (deque.front() <li>窗口形成后(即 <code>i >= k - 1),nums[deque.front()] 就是当前窗口最大值

为什么不能只存值,必须存下标?

因为要判断队首元素是否“过期”——窗口滑动后,旧最大值可能已不在当前范围内。如果只存 nums[i] 值,根本不知道它对应哪个位置,也就无法判断该不该删。

  • 存下标能同时获得值和位置信息:nums[deque.front()] 取值,deque.front() 判断是否越界
  • 数组有重复值时,仅靠值无法区分先后顺序,下标天然带顺序属性
  • std::deque 支持 O(1) 首尾增删,比 std::vector 更合适

边界处理最容易漏掉的三个点

实际写的时候,这几个地方一漏就返回空结果或越界崩溃:

  • 输入 k == 0nums.empty() 必须提前返回空 vector,不然循环直接崩
  • 窗口大小 k > nums.size() 是合法输入,此时应返回空结果,不是报错
  • 初始化阶段(i )不往答案里 push,但下标仍要入队、去尾——否则第一个窗口算不准

c++11 后推荐用 emplace_backfront() 而非 push_back[0]

效率和可读性都更好,而且避免对 deque 做随机访问误操作。

立即学习C++免费学习笔记(深入)”;

  • deque.emplace_back(i)deque.push_back(i) 少一次拷贝
  • 始终用 deque.front()deque.back(),别用 deque[0]deque[deque.size()-1]——后者在空队列时未定义行为
  • 迭代变量用 size_t i 要小心:当 i 且 <code>k==1 时,i-1 会绕成极大正数,建议统一用 int i

下标管理、越界检查、空队列防御——这三块不写进循环体里,光靠“单调性”推导很容易在实测时卡住半天。

text=ZqhQzanResources