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

239.滑动窗口最大值

leetcode原题链接

题目描述:

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值

示例1:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       31 [3  -1  -3] 5  3  6  7       31  3 [-1  -3  5] 3  6  7       51  3  -1 [-3  5  3] 6  7       51  3  -1  -3 [5  3  6] 7       61  3  -1  -3  5 [3  6  7]      7

示例2

输入:nums = [1,3,0,2,4]
输出:0
解释:
nums 无论怎么变化总是有 3 分。
所以我们将选择最小的 k,即 0。

提示

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • 1 <= k <= nums.length

解题思路:

方法一:单调队列

单调队列:队列中的元素是单调递增或单调递减的队列就是单调队列。


  1. 维护队列中的元素递增

对于这道题需要维护一个单调递增的队列。
在这里插入图片描述

由队尾到队头 元素是单调递增的。如果要入队元素大于队尾元素,则队尾元素出队,这是个循环操作,如下:

while(deque.peekLast() < newElement){deque.pollLast();
}
deque.push(newElement); // 新元素入队

  1. 如何保证队列中的元素是窗口内的,因为窗口一直在向右移动?

在这里插入图片描述

初始时,窗口为1,队列中元素为9, 8, 7。窗口向右移动时(窗口2)发现9已不是窗口中的元素,但9依然在队列中,且9为队列的队头元素,需要将9从队列的队头弹出。所以需要进行如下判断:

if(deque.peekFirst() == v){ // v为上一个窗口最左边的值。deque.poolFirst();
}

整体代码如下:

public int[] maxSlidingWindow(int[] nums, int k) {int n = nums.length;int[] ans = new int[n - k + 1];Deque<Integer> deque = new LinkedList<>();int idx = 0;for(int i = 0; i < nums.length; i++){// 保证队列中的元素是窗口内的if(!deque.isEmpty() && i - k>= 0 && nums[i - k] == deque.peekFirst()){deque.pollFirst();}// 维护队列中的元素是递增的while (!deque.isEmpty() && nums[i] > deque.peekLast()){deque.pollLast();}deque.addLast(nums[i]);if(i>= k - 1){ans[idx++] = deque.peekFirst();}}return ans;
}

方法二:线段树

百度百科:线段树


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fEboTtnz-1690452411315)(D:\ProgramFiles\Typora\typora-images\image-20230727175053720.png)]

线段树中的每个节点存储的是这个区间的最大值。

整体代码如下:

public int[] maxSlidingWindow(int[] nums, int k) {int len = nums.length;int[] ans = new int[len - k + 1];this.tr = new Node[len * 4+1];build(1,1,len);for(int i = 0; i<len;i++){update(1,i+1,nums[i]);}for(int i = 0; i< len -k+1;i++){ans[i] = query(1,i+1,i+k);}return ans;
}class Node {int l, r, v;Node(int l, int r) {this.l = l;this.r = r;v = Integer.MIN_VALUE;}
}Node[] tr;void pushup(int u) {tr[u].v = Math.max(tr[u << 1].v, tr[u << 1 | 1].v);
}void build(int u, int l, int r) {tr[u] = new Node(l, r);if (l != r) {int mid = tr[u].l+tr[u].r >> 1;build(u << 1, l, mid);build(u << 1 | 1, mid + 1, r);}
}void update(int u, int x, int v){if(x== tr[u].l&&tr[u].r==x){tr[u].v = Math.max(tr[u].v, v);} else{int mid = tr[u].l+tr[u].r>>1;if(x<=mid){update(u<<1,x,v);} else{update(u<<1|1,x,v);}pushup(u);}
}
int query(int u, int l, int r){if(l<= tr[u].l&&tr[u].r<=r){return tr[u].v;} else{int mid = tr[u].l+tr[u].r>>1;int ans = Integer.MIN_VALUE;if(l<=mid){ans =query(u<<1,l,r);} if(r>mid){ans = Math.max(query(u<<1|1,l,r),ans);}return ans;}
}
http://www.lryc.cn/news/97448.html

相关文章:

  • Redis基础原理
  • .NET 5 Web API 中JWT详细教程:保护你的Web应用
  • MyBatis-Plus自动填充
  • Dubbo服务提供者失效踢出原理解析
  • el-select下拉框处理分页数据,触底加载更多
  • 如何设计自动化测试脚本?一文5个步骤带你从0到1设计
  • PostgreSQL实战-数据库迁移部署
  • PHP数据库
  • Mybatis的基本操作--增删改查
  • Qt简单实现密码器控件
  • fpga_pwm呼吸灯(EP4CE6F17C8)
  • WPF实战学习笔记20-设置首页启动页
  • uniapp实现预约时间选择弹窗组件
  • opencv 之 外接多边形(矩形、圆、三角形、椭圆、多边形)使用详解
  • 断路器分合闸速断试验
  • 【Redis】如何实现一个合格的分布式锁
  • 组件化开发复习
  • 【设计模式】设计原则-里氏替换原则
  • v2ex站点base64编码解码
  • PostgreSQL数据库动态共享内存管理器——Dynamic shared memory areas
  • Redission分布式锁详解
  • 063、故障处理之快速恢复数据
  • 从零开始学习CTF
  • 【stable diffusion】保姆级入门课程05-Stable diffusion(SD)图生图-涂鸦重绘的用法
  • HBase 源码编译部署包
  • 备战秋招 | 笔试强训16
  • 01 Excel常用高频快捷键汇总
  • PHP Laravel 路由、中间件、数据库等例子
  • Unity小游戏——使被砍中的怪物四处飞散
  • hive之文件格式与压缩