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

每日算法刷题Day60:8.10:leetcode 队列5道题,用时2h

三、双端队列

1.套路

1.反转就当做双端队列换一个方向处理

2.题目描述

1.你的笔记本键盘存在故障,每当你在上面输入字符 'i' 时,它会反转你所写的字符串。而输入其他字符则可以正常工作。
给你一个下标从 0 开始的字符串 s ,请你用故障键盘依次输入每个字符。
返回最终笔记本屏幕上输出的字符串。(答案)

3.学习经验
1. 2810. 故障键盘(简单)

2810. 故障键盘 - 力扣(LeetCode)

思想

1.你的笔记本键盘存在故障,每当你在上面输入字符 'i' 时,它会反转你所写的字符串。而输入其他字符则可以正常工作。
给你一个下标从 0 开始的字符串 s ,请你用故障键盘依次输入每个字符。
返回最终笔记本屏幕上输出的字符串。
2.不用字符串的反转函数,而是把反转完插入字符当做往字符串另一端后面插入字符,即首部和尾部都要插入字符,故想到双端队列。
然后双端队列天然的有迭代器begin().end()rbegin(),rend(),所以可以直接放入string中,可以利用assign方法,或者直接利用string构造

代码
class Solution {
public:string finalString(string s) {int n = s.size();bool tag = true;deque<char> deq;for (int i = 0; i < n; ++i) {if (s[i] == 'i')tag = !tag;else if (tag) {deq.push_back(s[i]);} else {deq.push_front(s[i]);}}string res;if (tag)res.assign(deq.begin(), deq.end());elseres.assign(deq.rbegin(), deq.rend());return res;}
};

string构造

return tag ? string(deq.begin(), deq.end()): string(deq.rbegin(), deq.rend());

四、单调队列

1.套路

个人觉得叫单调双端队列更准确。
单调队列 = 滑动窗口 + 单调栈
2.
问:入队、出队、更新答案,这三步的顺序如何思考?
答:有两种情况。
如果更新答案时,用到的数据包含当前元素,那么就需要先入队,再更新答案;
如果用到的数据不包含当前元素,那么就需要先更新答案,再入队。
至于出队,一般写在前面,每遍历到一个新的元素,就看看队首元素是否失效(不满足要求),失效则弹出队首。
单调队列{双端队列{移除最左边的元素(不满足条件的无用数据/不在窗口内的数据)移除最右边的元素(不满足条件的无用数据)在最右边插入元素(窗口向右滑动)单调性从队首到队尾单调递减(删除无用数据,保证队列有序)\textbf{单调队列} \left \{ \begin{array}{l} \textbf{双端队列} \left \{ \begin{array}{l} \text{移除最左边的元素(不满足条件的无用数据/} \\ \hspace{9em}\text{不在窗口内的数据)}\\ \text{移除最右边的元素(不满足条件的无用数据)}\\ \text{在最右边插入元素(窗口向右滑动)} \end{array} \right. \\[4pt] \textbf{单调性} \qquad \text{从队首到队尾单调递减(删除无用数据,}\\ \hspace{16em}\text{保证队列有序)} \end{array} \right. 单调队列双端队列移除最左边的元素(不满足条件的无用数据/不在窗口内的数据)移除最右边的元素(不满足条件的无用数据)在最右边插入元素(窗口向右滑动)单调性从队首到队尾单调递减(删除无用数据,保证队列有序)
3.套路:

  • 1.右边入(元素进入队尾,同时维护队列单调性)
  • 2.左边出(元素离开队首)
  • 3.记录/维护答案(根据队首)
class Solution {
public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {int n = nums.size();vector<int> res(n - k + 1); // 窗口个数deque<int> deq;             // 双端队列// 枚举右端点for (int i = 0; i < n; ++i) {// 右边入while (!deq.empty() && nums[deq.back()] <= nums[i]) {deq.pop_back(); // 维护单调性}deq.push_back(i);// 左边出int left = i - k + 1; // 窗口左端点if (deq.front() < left)deq.pop_front();// 记录答案if (left >= 0)res[left] = nums[deq.front()]; // 队列从队首到队尾单调递减,队首就是窗口最大值}return res;}
};
2.题目描述

1(学习).给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值(答案) 。
2(重点学习).请设计一个自助结账系统(答案),该系统需要通过一个队列来模拟顾客通过购物车的结算过程,需要实现的功能有:

  • get_max():获取结算商品中的最高价格,如果队列为空,则返回 -1
  • add(value):将价格为 value 的商品加入待结算商品队列的尾部
  • remove():移除第一个待结算的商品价格,如果队列为空,则返回 -1
    注意,为保证该系统运转高效性,以上函数的均摊时间复杂度均为 O(1)
    3.给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度(答案),该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit 
    如果不存在满足条件的子数组,则返回 0 。
    4.给你一个下标从 0 开始的整数数组 nums 。nums 的一个子数组如果满足以下条件,那么它是 不间断 的:
  • ii + 1 ,…,j  表示子数组中的下标。对于所有满足 i <= i1, i2 <= j 的下标对,都有 0 <= |nums[i1] - nums[i2]| <= 2 。
    请你返回 不间断 子数组的总数目(答案)
    子数组是一个数组中一段连续 非空 的元素序列。
3.学习经验

1.快速获得一个滑动窗口中的最值想到用单调队列

1. 239. 滑动窗口最大值(困难,学习)

239. 滑动窗口最大值 - 力扣(LeetCode)

思想

1.给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
2.此题要得到滑动窗口的最大值,首先滑动窗口肯定要左边出,右边进,而得到最大值最好维护一个单调性,所以想到单调队列。
按照套路:

  • 1.右边入:不符合要求的元素右边出,维护单调性
  • 2.左边出:不在窗口内的元素出
  • 3.得到答案
代码
class Solution {
public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {int n = nums.size();vector<int> res(n - k + 1); // 窗口个数deque<int> deq;             // 双端队列// 枚举右端点for (int i = 0; i < n; ++i) {// 右边入while (!deq.empty() && nums[deq.back()] <= nums[i]) {deq.pop_back(); // 维护单调性}deq.push_back(i);// 左边出int left = i - k + 1; // 窗口左端点if (deq.front() < left)deq.pop_front();// 记录答案if (left >= 0)res[left] = nums[deq.front()]; // 队列从队首到队尾单调递减,队首就是窗口最大值}return res;}
};
2. LCR 184.设计自助结算系统(中等,重点学习)

LCR 184. 设计自助结算系统 - 力扣(LeetCode)

思想

1.请设计一个自助结账系统,该系统需要通过一个队列来模拟顾客通过购物车的结算过程,需要实现的功能有:

  • get_max():获取结算商品中的最高价格,如果队列为空,则返回 -1
  • add(value):将价格为 value 的商品加入待结算商品队列的尾部
  • remove():移除第一个待结算的商品价格,如果队列为空,则返回 -1
    注意,为保证该系统运转高效性,以上函数的均摊时间复杂度均为 O(1)
    2.首先以O(1)入队和出队队列就能实现,难的是O(1)获得最大值。
    正常能想到用一个最大值变量维护,一个队列模拟,但是当该队列的最大值出栈时,最大值变量无法去找到下一个最大值进行更新,行不通。
    所以想到用一个单调队列来维护最大值,即一个单调的双端队列。
    只有当队列的队首跟单调队列的队首一样时,单调队列才移出队首。
    然后单调队列移入队尾时要维护单调性。
代码
class Checkout {
public:queue<int> que; // 维护原顺序deque<int> deq; // 维护最大值Checkout() {}int get_max() {if (deq.empty())return -1;return deq.front();}void add(int value) {que.push(value);while (!deq.empty() && deq.back() < value)deq.pop_back(); // 不是小于等于deq.push_back(value);}int remove() {if (que.empty())return -1;else if (que.front() == deq.front())deq.pop_front();int x = que.front();que.pop();return x;}
};/*** Your Checkout object will be instantiated and called as such:* Checkout* obj = new Checkout();* int param_1 = obj->get_max();* obj->add(value);* int param_3 = obj->remove();*/
3. 1438. 绝对差不超过限制的最长连续子数组(中等)

1438. 绝对差不超过限制的最长连续子数组 - 力扣(LeetCode)

思想

1.给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit 
如果不存在满足条件的子数组,则返回 0 。
2.首先,这是典型的不定长滑动窗口,是求最长类型
然后要快速的得到滑动窗口的最大值和最小值,典型的单调队列,用两个单调队列,一个维护最大值,一个维护最小值,都记录下标。

代码
class Solution {
public:int longestSubarray(vector<int>& nums, int limit) {int n = nums.size();deque<int> deqMax;deque<int> deqMin;int l = 0, res = 0;for (int r = 0; r < n; ++r) {while (!deqMax.empty() && nums[deqMax.back()] < nums[r])deqMax.pop_back();while (!deqMin.empty() && nums[deqMin.back()] > nums[r])deqMin.pop_back();deqMax.push_back(r);deqMin.push_back(r);while (l <= r &&nums[deqMax.front()] - nums[deqMin.front()] > limit) {++l;if (!deqMax.empty() && deqMax.front() < l)deqMax.pop_front();if (!deqMin.empty() && deqMin.front() < l)deqMin.pop_front();}// [l,r]满足条件res = max(res, r - l + 1);}return res;}
};
4. 2762. 不间断子数组(中等)

2762. 不间断子数组 - 力扣(LeetCode)

思想

1.给你一个下标从 0 开始的整数数组 nums 。nums 的一个子数组如果满足以下条件,那么它是 不间断 的:

  • ii + 1 ,…,j  表示子数组中的下标。对于所有满足 i <= i1, i2 <= j 的下标对,都有 0 <= |nums[i1] - nums[i2]| <= 2 。
    请你返回 不间断 子数组的总数目。
    子数组是一个数组中一段连续 非空 的元素序列。
    2.跟[[八、队列#3. 1438. 绝对差不超过限制的最长连续子数组(中等)]]一模一样,只不过答案从求长度最大值变成求子数组数目了。
代码
class Solution {
public:long long continuousSubarrays(vector<int>& nums) {int n = nums.size();long long res = 0;deque<int> deqMax;deque<int> deqMin;int l = 0;for (int r = 0; r < n; ++r) {while (!deqMax.empty() && nums[deqMax.back()] < nums[r])deqMax.pop_back();while (!deqMin.empty() && nums[deqMin.back()] > nums[r])deqMin.pop_back();deqMax.push_back(r);deqMin.push_back(r);while (l <= r && nums[deqMax.front()] - nums[deqMin.front()] > 2) {++l;if (!deqMax.empty() && deqMax.front() < l)deqMax.pop_front();if (!deqMin.empty() && deqMin.front() < l)deqMin.pop_front();}// [l,r]符合条件,共r-l+1个res += r - l + 1;}return res;}
};
http://www.lryc.cn/news/615798.html

相关文章:

  • 机器学习-增加样本、精确率与召回率
  • Modbus RTU转Profinet网关接在线循环Na离子实现PLC读取温度值
  • C# 中常用集合以及使用场景
  • 本地WSL部署接入 whisper + ollama qwen3:14b 总结字幕增加利用 Whisper 分段信息,全新 Prompt功能
  • Framework开发之Zygote进程2(基于开源的AOSP15)--init.rc在start zygote之后的事情(详细完整版逐行代码走读)
  • 《解锁 C++ 基础密码:输入输出、缺省参数,函数重载与引用的精髓》
  • 【Linux | 网络】数据链路层
  • 九、Linux Shell脚本:运算符与表达式
  • 开启单片机
  • 服务器硬件电路设计之 I2C 问答(三):I2C 总线上可以接多少个设备?如何保证数据的准确性?
  • 笔试——Day34
  • 亚麻云之全球加速器——CloudFront(CDN)服务入门
  • 【Docker实战】Spring Boot应用容器化
  • ShadowKV 机制深度解析:高吞吐长上下文 LLM 推理的 KV 缓存“影子”方案
  • Python爬虫-爬取政务网站的文档正文内容和附件数据
  • 【后端】Java 8 特性 `User::getId` 语法(方法引用)介绍
  • 【东枫科技】NTN-IOT 卫星互联网原型系统,高达1.6G大带宽
  • MPLS特性之PHP(Penultimate Hop Popping)
  • Android快速视频解码抽帧FFmpegMediaMetadataRetriever,Kotlin(2)
  • 【软考中级网络工程师】知识点之 DCC 深度剖析
  • 【21】OpenCV C++实战篇——OpenCV C++案例实战二十七《角度测量》
  • Perplexity 为特朗普 Truth Social 提供技术支持
  • 如何培养自己工程化的能力(python项目)
  • Pytorch深度学习框架实战教程12:Pytorch混合精度推理,性能加速147%的技术实现
  • 若依前后端分离版学习笔记(八)——事务简介与使用
  • Apache Pulsar性能与可用性优化实践指南
  • NLP---IF-IDF案例分析
  • C++高频知识点(十九)
  • 【面试场景题】异地多活改造方案
  • 【Matplotlib】中文显示问题