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

算法-堆+单调栈

首先堆在我们的Java中我们的是一个优先队列类

PriorityQueue

然后我们要弄最大堆和最小堆

最大堆:

PriorityQueue<Integer> pq = new PriorityQueue<Integer>((a, b) -> b - a);

最小堆:

PriorityQueue<Integer> pq = new PriorityQueue<Integer>((a, b) -> a-b);


1046最后一块石头的重量

我们让最大的和第二大的石头相撞,我们就能得到最小的结果

所以我们维护一个最大堆

PriorityQueue<Integer> pq = new PriorityQueue<Integer>((a, b) -> b - a);


2558从数量最多的堆取走礼物


3264K次乘数运算后的最终数组

我们还有一种思路是

我们往堆里面存的类型是数组

ProityQueue<int[]>

然后【0】是我们的值

【1】是我们的这个元素的下标

两个元素按值的大小排序,当值相同是按照谁的下标靠前来排序

PriorityQueue<int[]> pq = new PriorityQueue<int[]>((a, b) -> a[0] != b[0] ? a[0]-b[0] : a[1]-b[1]);


2530执行k次操作后的最大分数


单调栈

739每日温度

我们遇到第一个不是递增的温度的时候,我们前面的节点计算就结束了

所以我们用个,来存我们的单调递增的天的下标

然后用变量i,来往后遍历

当遇到我们的第一个不是递增的温度时

我们用 当前变量i减去栈中天的下标

然后把距离差记录到我们的数组里


1475商品折扣后的最终价格

我们的栈是从右往左收集的

看看我们的收集情况和弹出情况

收集:

我们从右往左进行收集我们的元素的值

弹出情况:

如果我们遍历到i这个位置,我们的price【i】比我们栈元素

说明我们不能打折,我们要右边小于左边才能打折

所以我们不断弹出,直到遇见第一个比我们小的数字,如果stack为空那就是不打折,不为空那就是打折

ps:如果右边弹出完,然后继续遍历左边的值是否有影响?因为我们用不到数组右边那一大段了

不会,因为我们能弹出,就是因为当前元素比栈元素

所以当前元素又是最靠左,又比之前栈里的元素小,所以之前右边的元素弹出没有用到就无所谓了


503下一个更大元素


962最大宽度坡

我们首先维护一个单调递减的栈

然后把我们单调递减的值对应的下标放到我们的栈里面

然后我们要求最远距离

所以我们就从右往左进行遍历

为啥一满足条件,就把栈里的元素弹出呢?

因为我们最右边,肯定才是最远的,我们从右往左遍历,最右边那个值n和i的位置的差值

肯定比n-1和i位置的差值大

所以栈里的这个元素的位置,已经没必要使用了


853车队

首先我们要有个Time【】数组,记录各个位置到终点target的时间(起始的时候,每个位置只有一辆车)

然后我们用一个栈来维护我们的结果

因为我们是从地点0往地点target开始遍历的,

所以我们在前面的地点,遇到比我们花费时间久的,也就是我前面地点的Time花费比我后面地点的Time多

就说明他会卡住我们,形成一个车队

所以我们把栈里的pop出,把这个前面的慢车+进去

遇到前面比我们花费时间少的,加进去

说人话,

time【i】>栈里车耗费的时间

我们就把栈里的弹出来,然后把i这个位置的车当作一个组放进去

time【i】<栈里车耗费的时间

说明我们追不上前面,我们把它当作一个组放进去


1124表现良好的最长时间段

前缀知识:前缀和

单调栈解法

劳累天的值为1

不劳累天的值为-1

然后我们要求和>1的最长子数组

看看代码

我们计算前缀和

然后维护一个前缀和单调递减的栈,栈里面存的是我们位置的下标

(说一下为什么我们的栈要单调递减,跳过的比它大的元素怎么办

首先我们的栈是从左往右遍历,而我们的差值的计算是从右往左

例如

3 5 2 1 4

3 5 2 1 6

我们的栈里面是【3,2,1】为啥5没用呢,因为我们从右往左遍历我们遇到的数字有这样的情况

nums【j】>3但是nums【j】<5 这样子的情况,我们就不用考虑5 例如第一个例子 4>3 4<5

nums【j】>5>3 考虑5的情况,也明显是左边的3更远,所以5根本没用 第二个例子 6>5>3

所以单调递减栈外那些比我们栈内元素值大的元素我们都没必要去考虑,你看我们分析的情况下那值对我们根本没影响

然后我们从后往前遍历,来算两个位置之间的差值,然后我们的ans保存差值的最大值


(重要)132模式

我们的位置是 i <j <k

然后我们要求的是

nums【j】>nums【k】>nums【i】

其实我们也想到了,这个就是枚举而已,但是我们要枚举哪个好一点呢?

如何在确定一个数后快速找到另外两个数

枚举 i

由于 i 是 132 结构中最小的数,那么相当于我们要从 i 后面,找到一个对数 (j,k),使得 (j,k) 都满足比 i 大,同时 j 和 k 之间存在 j > k 的关系。由于我们的遍历是单向的,因此我们可以将问题转化为找 k,首先 k 需要比 i 大,同时在 [i, k] 之间存在比 k 大的数即可

枚举 j

由于 j 是 132 结构里最大的数,因此我们需要在 j 的右边中比 j 小的「最大」的数,在 j 的左边找比 j 小的「最小」的数。这很容易联想到单调栈,但是朴素的单调栈是帮助我们找到左边或者右边「最近」的数,无法直接满足我们「最大」和「最小」的要求,需要引入额外逻辑。

枚举 k

由于 k 是 132 结构中的中间值,这里的分析逻辑和「枚举 i」类似,因为遍历是单向的,我们需要找到 k 左边的 i,同时确保 [i,k] 之间存在比 i 和 k 大的数字

开始我们的答案解析

处理过程:

我们从后往前做,维护一个「单调递减」的栈,同时使用 k 记录所有出栈元素的最大值k 代表满足 132 结构中的 2)

我们从后往前进行遍历

我们出栈的条件是nums【i】>deque.peeLast()

如果我们的K有值的话,就说明我们满足了(J>K)

看看我们的K的逻辑

我们是单调栈不满足单调递减的时候弹出,此时我们的K才有值,不满足单调递减说明我们已经找到了(J>K)所以我们后面就剩找K>i了

这就是为啥我们的nums【i】<k的时候我们return true


矩形面积

42接雨水

相关文章:

  • TCP/IP和UDP协议的发展历程
  • PHP腾讯云人脸核身生成 SDK 接口调用步骤使用签名
  • 第十四节:实战场景-何实现全局状态管理?
  • Java 高并发核心:线程池使用详解 + 自定义参数配置全剖析(附源码+面试解析)
  • 【实体转换】mapstruct详解
  • 基于Flask的AI工具聚合平台技术解析
  • idea 许可证过期
  • HTML理论题
  • YOLOV4在RTX 4090 Ubuntu 24.04 LTS 下的实践总结
  • C++17 新特性简解
  • 无人机在农业中的应用与挑战!
  • 如何才能学会代数几何,代数几何的前置学科是什么
  • uniapp打包IOS私钥证书过期了,如何在非mac系统操作
  • 【项目管理】第19章 配置与变更管理-- 知识点整理
  • 观察者模式详解与C++实现
  • STM32---GPIO
  • 极狐GitLab 议题和史诗创建的速率限制如何设置?
  • 2025-04-18 李沐深度学习3 —— 线性代数
  • Windows软件界面分析软件-控件识别工具
  • echarts饼图中心呈现一张图片,并且能动态旋转的效果react组件
  • 今年底,全国新拍电视剧、纪录片将基本实现超高清化
  • 日本首相石破茂向靖国神社献祭品
  • 春山谷雨前,并手摘芳烟
  • 成都一医院孕妇产下七胞胎?涉事医院辟谣:信息不实已举报
  • 部分人员无资质展业、投资建议无合理依据,天相财富被责令改正
  • 2025年世界互联网大会亚太峰会人工智能大模型论坛举行