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

leetcode_239 滑动窗口最大值

1. 题意

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧

移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。

滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 。

2. 题解

2.1 优先队列

一般最大(小)值都可以尝试用一下优先队列来做一下,刚开始没想到,

看题解有这种做法,因此来补一下。由于不仅仅需要维护值,还需要

注意下标有没有出窗口,因此我们需要维护一个pairpairpair,值和元素的

下标。

  • 自定义比较规则
class Solution {
public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {int n = nums.size();vector<int> ans;auto cmp = [](const pair<int,int> &a, const pair<int,int> &b) {if (a.second != b.second)return a.second < b.second;return a.first < b.first;};priority_queue< pair<int,int>, vector<pair<int,int>>, decltype(cmp)> pq(cmp);for (int i = 0; i < n; ++i) {pq.emplace( i, nums[i] );while (pq.top().first <= i - k) {pq.pop();}if (i >= k - 1)ans.push_back( pq.top().second );}return ans;}
};
  • 使用pair默认的比较规则
class Solution {
public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {int n = nums.size();vector<int> ans;priority_queue<pair<int,int>> q;for (int i = 0;i < n; ++i) {q.emplace( nums[i], i);while  ( i >= k && !q.empty() && q.top().second <= i - k) {q.pop();}if ( i >= k - 1) {ans.push_back( q.top().first );}}return ans;}
};

时间复杂度O(nlog⁡2n)O(n\log_2 n)O(nlog2n)

空间复杂度O(n)O(n)O(n)

2.2 单调队列

对于新加入的元素,如果它的前面有小于等于它的元素,显然会被它

屏蔽掉。因此队列中在它前面的只有比它大的元素,因此这个队列满足

单调性,是一个单调递减队列。

相当于公司招聘程序员,新来的比老员工好用就裁掉老员工。就算老员

工能力强,超过了35岁也裁掉。

由于需要从尾部添加和删除元素,因此选择dequedequedeque这种数据结构。

class Solution {
public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {int n = nums.size();// 10 2 3 4 5 vector<int> ans;deque<int> q;int hd = -1;int tl = 0;for (int i = 0; i < n; ++i) {if ( i >= k && (!q.empty() && q.front() == i - 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;}
};

时间复杂度O(n)O(n)O(n)

空间复杂度O(k)O(k)O(k)

2.3 分块+预处理

可以将数组每kkk个分成一块,求出这kkk个元素的前后缀。

对于任意一个长度为kkk的子串,必然可以由

suf[i]suf[i]suf[i]pre[i+k−1]pre[i + k -1]pre[i+k1]组成。

当然你也可以划分成suf[i−(k−1)]suf[i - (k - 1)]suf[i(k1)]pre[i]pre[i]pre[i]

只是需要注意下下标。

这种分块预处理的方法还是很巧妙的。

我们直接预处理整个数组,pre[i]pre[i]pre[i]表示的是i−i%ki-i\%kii%kiii的最大值;

suf[i]suf[i]suf[i]表示的是iii⌈i/k⌉k−1\lceil i / k \rceil k-1i/kk1的最大值。

在处理时i%k==0i\%k==0i%k==0时,pre[i]=nums[i]pre[i]=nums[i]pre[i]=nums[i]

(i+1)%k==0(i+1)\%k==0(i+1)%k==0时,suf[i]=nums[i]suf[i] = nums[i]suf[i]=nums[i]

注意在i=n−1i=n-1i=n1时,suf[i]=nums[i]suf[i]=nums[i]suf[i]=nums[i]

class Solution {
public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {int n = nums.size();vector<int> ans;vector<int> pre(n);vector<int> suf(n);for (int i = 0;i < n; ++i) {if ( i % k == 0)pre[i] = nums[i];elsepre[i] = max( pre[i - 1], nums[i]);}for (int i = n - 1; ~i; --i) {if (i % k == k - 1 || i == n - 1) {suf[i] = nums[i];}else {suf[i] = max(suf[i + 1], nums[i]);}}// pre[i]: pre[i % k]// for (int i = 0; i <= n - k; ++i) {//     ans.push_back( max(suf[i], pre[i + k - 1]) );//     // why not pre[i] suf[i - (k - 1)]// }for (int i = k - 1; i < n; ++i) {ans.push_back( max(pre[i], suf[i - (k - 1)]));}return ans;}
};

时间复杂度O(n)O(n)O(n)

空间复杂度O(n)O(n)O(n)

当然上面的做法是官解,我自己的做法用的是麻烦的

滚动数组的做法,调起来是真的麻烦。

class Solution {
public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {int n = nums.size();vector<int> ans;vector< vector<int> > pre(2, vector<int>( k + 1, INT_MIN) );vector< vector<int> > suf(2, vector<int>( k + 1, INT_MIN) );int cur = 0;for (int i = 1;i <= k && i <= n; ++i) {pre[cur][i] = max( pre[cur][i - 1], nums[i - 1]);int suf_idx = n < k ? n - i : k - i;suf[cur][i] = max( suf[cur][i - 1], nums[ suf_idx ]);}ans.push_back( pre[cur][n < k ? n : k]);for (int s = k; s < n; s += k) {cur ^= 1;for (int j = 1; j <= k && (s + j) <= n; ++j) {pre[cur][j] = max( pre[cur][j - 1], nums[s + j - 1]);int suf_idx = s + k - j  < n ?  s + k - j : n - j;suf[cur][j] = max( suf[cur][j - 1], nums[ suf_idx ]);if (j == k) {ans.push_back( pre[cur][k]);}else {ans.push_back( max(suf[cur ^ 1][k - j], pre[cur][j]) );}}fill( pre[cur ^ 1].begin(), pre[cur ^ 1].end(), INT_MIN);fill( suf[cur ^ 1].begin(), suf[cur ^ 1].end(), INT_MIN);// memset(&pre[cur ^ 1], INT_MIN, sizeof(pre[cur ^ 1]));// memset(&suf[cur ^ 1], INT_MIN, sizeof(suf[cur ^ 1]));}return ans;}
};

时间复杂度O(n)O(n)O(n)

空间复杂度O(k)O(k)O(k)

3. 参考

leetcode

0x3f

http://www.dtcms.com/a/339119.html

相关文章:

  • 本地部署消息中间件 Weblogic 并实现外部访问
  • 2025年9月计算机二级MySQL题库及wampserver2.2e下载安装教程
  • 解决linux中磁盘爆满(准确说是文件系统爆满)导致mysql启动失败的问题——对文件系统进行扩容
  • Chrome 插件开发实战技术文章大纲
  • 前端国际化(i18n)解决方案深度比较
  • C#项目集成海康SDK指南:从搭建环境到实现视频预览、录制、截屏
  • 从H.264到AV1:音视频技术演进与模块化SDK架构全解析
  • ComfyUI部署Wan2.2,开放API,文生视频与图生视频
  • 基于Python的宠物服务管理系统 Python+Django+Vue.js
  • 农村污水处理行业物联网解决方案
  • Vue3 el-table实现 将子表字段动态显示在主表行尾
  • GaussDB 中 alter default privileges 的使用示例
  • 鱼骨图图片制作全指南:使用工具推荐 + 行业案例
  • Python实战:SEO优化自动化工具开发指南
  • 大数据毕业设计选题推荐:护肤品店铺运营数据可视化分析系统详解
  • Android面试指南(三)
  • 在Excel和WPS表格中为多个数字同时加上相同的数值
  • 从接口自动化测试框架设计到开发(三)主流程封装、返回数据写入excel
  • 【iOS】内存管理
  • 如何在 Ubuntu Linux 上安装 RPM 软件包
  • 在 Windows 上使用 Kind 创建本地 Kubernetes 集群并集成Traefik 进行负载均衡
  • 2025年8月16日(星期六):雨骑古莲村游记
  • [优选算法专题二——找到字符串中所有字母异位词]
  • 网络间的通用语言TCP/IP-网络中的通用规则4
  • Java网络编程:TCP与UDP通信实现及网络编程基础
  • C语言—指针(针对小白版)
  • 算法学习day19----博弈论模型--取石子游戏(Python)
  • 懒加载机制实现子模块按需动态导入
  • 全平台轻量浏览器推荐|支持Win/macOS/Linux,极速加载+隐私保护+扩展插件,告别广告与数据追踪!
  • RT-Thread Nano移植到STM32心得(基于GCC、HAL库)