当前位置: 首页 > news >正文

子串——滑动窗口最大值

我们用一个双端队列deque,只存数组下标,并且保证:
队头 = 当前窗口最大值的下标
队列里的数从大到小排列

普通队列(queue):只能队尾进,队头出
双端队列(deque = double ended queue)两头都能插,都能删

为什么滑动窗口必须用deque?
因为我们要做两件事:
删队头(过期的最大值)
删队尾(比新数小的,没用了)++

每一步做4件事:

1、删过期
队头如果不在窗口里,删掉。判断队头是否在当前的窗口内,关键是理解:当i=k-1(即窗口大小为k)时开始形成窗口,之后随着for循环中i的移动,窗口跟着滑动,而队列存的是数组的下标,如果队头的元素dq.front()<=i-k,i-k刚好是当前i所在窗口外的那个元素的下标,说明这个元素已经过期(不属于当前窗口)因此要弹出,dq.pop_front(),那么我们是怎么判断队头是否过期了呢:因为队列存的是下标,所以我们可以通过公式dq.front()<=i-k来判断,虽然队列里有删除操作小元素的操作,但是不影响我们对队头元素是否在窗口内的判断,我们关注的是队头是否在窗口内,确保在窗口内后我们才能把它作为当前窗口的最大值,第二步的弹出操作则是通过删除更小值来确保队头最大,也就是说我们通过前面两步来找到当前窗口的最大值

2、删小数
队尾比当前数小,永远不可能成为最大值,直接删掉。解释:为了保证队头就是当前窗口的最大值,如果此时队头的元素比当前遍历到的元素nums[i]小,就弹出:dq.pop_back()。这样才能保证队头最大。之后我们直接把通过队头的下标把元素存到结果数组中

3、加当前数
把当前下标放进队列尾部。dq.push_back(i)

4、取答案
窗口形成后,队头就是当前窗口最大值
另外只有窗口形成的时候我们才能把队头下标对应元素存入到结果数组,因此我们要加入条件判断,if(i>=k-1)

补充第二步必须通过while循环来实现的,原因是:因为新进来的数可能比队列里好几个数都大,因此需要把里面的元素都删掉,既有条件又有循环最好的实现方式就是用while循环。第一步每次窗口只移动一位,最多只会有一个元素过期,就是队头元素,因此第一步我们除了while也可以用if来实现

完整代码实现如下:

#include
#include
#include // 双端队列,必须加头文件
using namespace std;

vector maxSlidingWindow(vector& nums, int k) {

vector<int> res;       // 存最终答案
deque<int> dq;         // 存下标,保证队头永远是当前窗口最大值for (int i = 0; i < nums.size(); i++) {// 1. 队头超出窗口范围,删掉while (!dq.empty() && dq.front() <= i - k) {dq.pop_front();}// 2. 队尾比当前数小,删掉(不可能成为最大值了)while (!dq.empty() && nums[dq.back()] <= nums[i]) {dq.pop_back();}// 3. 把当前数下标加入队列dq.push_back(i);// 4. 窗口形成了,开始记录答案if (i >= k - 1) {res.push_back(nums[dq.front()]);}
}
return res;

}

// 测试
int main() {

vector<int> nums = {1,3,-1,-3,5,3,6,7};
int k = 3;
vector<int> ans = maxSlidingWindow(nums, k);// 输出结果
for (int num : ans) {cout << num << " ";
}
// 输出:3 3 5 5 6 7
return 0;

}

http://www.jsqmd.com/news/546041/

相关文章:

  • 联想ThinkPad声卡驱动安装避坑指南:从E470到X1 Carbon的通用解法
  • PlayCover如何重塑Mac游戏体验?社交与云服务革新玩法深度解析
  • Vue3+AI聊天室:如何实现消息自动滚动和流式响应?
  • 383. 赎金信
  • 星露谷物语农场规划器:3步打造完美农场的终极指南
  • 计算机毕业设计springboot在线病患管理系统 基于SpringBoot的智慧医疗就诊服务平台设计与实现 基于Java Web的医院数字化门诊住院一体化系统开发
  • Zotero文献引用必看:3个隐藏设置让你的Word排版更专业
  • 电脑能登QQ却打不开网页?3分钟搞定DNS配置(Win10/11通用)
  • 保姆级避坑指南:用Gromacs 2024跑小分子-蛋白复合物MD模拟,从拓扑生成到结果分析
  • 内存检测工具Memtest86+全解析:从故障排查到系统稳定性测试
  • DLT Viewer诊断日志分析实战指南:快速掌握汽车电子系统调试的核心工具
  • 当多线雷达遇上RTK:一个能跑工业现场的SLAM方案
  • 微信支付回调通知收不到的5个隐藏坑(附.NET Core实战解决方案)
  • 医学图像分类实战:基于kvasir v2胃病数据集的深度卷积网络性能对比
  • 【Python】Hydra 与 OmegaConf:构建动态可维护的机器学习配置系统
  • GLM-OCR场景应用:教育资料数字化、商务文档信息抽取实战
  • 告别HttpListener!在WPF里优雅运行ASP.NET Core的3个实战技巧(.NET 8版)
  • 别再只会用Arduino了!用STM32 HAL库驱动42步进电机(TB6600驱动器)的保姆级教程
  • LPDDR5读训练避坑指南:DVFSC功能开启后,你的RL和tWCKPRE参数算对了吗?
  • 5G核心网运维日记:一次AMF重分配故障排查,我是如何定位网络切片选择问题的?
  • Modelsim仿真Objects窗口一片空白?别急着重装,试试这个被忽略的优化选项设置
  • Python实战:用Holt-Winters三参数指数平滑预测电商季节性销量(附完整代码)
  • HarmonyOS毕业设计避坑指南:你的‘智慧XX系统’为什么总被导师打回?
  • 语义通信:从理论到6G落地的关键技术演进与挑战
  • FAST-LIO2中的IMU与激光雷达时间对齐:原理与代码实现详解
  • 数字信号处理避坑指南:采样频率选错导致的频谱混叠案例分析
  • H5页面如何优雅跳转iOS App Store?解决点击后重复跳转的坑
  • 直流GIL绝缘子表面电荷积聚的电热耦合机理与电场畸变特性研究
  • 如何让微信聊天记录真正属于你:完整备份与分析终极指南
  • 保姆级教程:ROS1/ROS2下rosbag录制与播放的10个实战技巧(含脚本与launch文件)