【题目/算法训练】:单调队列单调栈

🚀 前言:

【算法】单调队列&&单调栈 可以在看完这篇文章后,再来写下面的题目

一、绝对差不超过限制的最长连续子数组

思路:

      1) 就相当于滑动窗口,维护滑动窗口内的两个值,一个是最大值,一个是最小值,如果当前滑动窗口的最大值和最小值的差值都不超过  limit ,说明滑动窗口内任意两个数的差值都不会超过  limit 

       2)由于需要维护两个值 ,因此我们需要两个单调队列,同时维护一个区间的值,一个去维护最大值,一个去维护最小值

       3) 由于要求最长连续子数组的长度,那么我们假设已经 有【l,r - 1】满足条件的最长子数组长度,然后尾指针向后移动一位,假设此时【l,r】的最大差值已经超过 limit,此时 应该向后移动,,这道题本质就是一个变长的滑动窗口,其长度是根据题目所给条件来进行调整。

class Solution {
public:
    int longestSubarray(vector<int>& nums, int limit) {
        //处理边界情况
        if (limit < 0) return 0;
      
        deque<int> min_q, max_q;
        int l = 0, ans = 1 ;
        min_q.push_back(0);
        max_q.push_back(0);

        for (int r = 1, n = nums.size(); r < n; r++) {
            while (!min_q.empty() && nums[r] < nums[min_q.back()]) min_q.pop_back();
            while (!max_q.empty() && nums[r] > nums[max_q.back()]) max_q.pop_back();
            min_q.push_back(r);
            max_q.push_back(r);

            if (nums[max_q.front()] - nums[min_q.front()] > limit) {
                if (min_q.front() == l) min_q.pop_front();
                if (max_q.front() == l) max_q.pop_front();
                l++;
            }
            ans = max(ans, r - l + 1);
        }
        return ans;
    }
};

二、最大矩形面积

思路:

 1) 假设我们现在可以切割出的最大矩形面积为S;

 2)此时矩形高度等于其范围内最矮木板的高度。

 3)假设最大矩形两边各有1号和2号两块木板,此时1和2号的高度比矩形高度要小,

 4) 以每一块木板作为矩形最大高度的基准值,然后枚举去判断能够可以切出来的最大面积。因此我们需要求该木板左右两边最近的1,2号木板,就可以用单调栈。

#include<iostream>
#include <vector>
#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
using namespace std;

typedef long long ll;

int main()
{
	int n;
	cin >> n;
	vector<ll> arr(n + 2, -1);  //让最左边和最右边木板旁边还有木板
	vector<ll> l(n + 2), r(n + 2);//分别存储左右两边小于第i块木板的那个下标
	for (int i = 1; i <= n; i++) cin >> arr[i];
	
	stack<ll>s;
	for (int i = 1; i <= n + 1; i++) {
		while (!s.empty() && arr[i] < arr[s.top()]) {
			r[s.top()] = i;
			s.pop();
		}
		s.push(i);
	}
	while (!s.empty()) s.pop();
	for (int i = n; i >= 0; i--) {
		while (!s.empty() && arr[i] < arr[s.top()]) {
			l[s.top()] = i;
			s.pop();
		}
		s.push(i);
	}
	ll ans = 0;
	for (int i = 1; i <= n; i++) { //以每一块木板为基准值切出的最大面积
		ll height = arr[i], width = r[i] - l[i] - 1;
		ans = max(ans, height * width);
	}
	cout << ans << "\n";
	return 0;
}

三、接雨水

首先由题目可知只有凹形才能接雨水,因此我们假设已经存在1号柱子到2号柱子如下构成的绿色接雨水面积,当再来了一个3号柱子,我们又可以新接一些雨水,即黄色面积,假设1号柱子的下标为i,3号柱子的下标为j,此时黄色部分的长度为 j - i,高度为min (h3 - h1) -h2

因此我们不断往后增加柱子,比如4号柱子,那里又可以增加红色雨水面积,加入5号柱子,计算不出我们可以接雨水的面积,再增加6号(仍然没有新增雨水的量),再加入7号柱子,

此时h7和h5可以算出可以接雨水的量,此时可以当作h6不存在,如下图所示

因此可知我们应该需要维护的就是上图中h4、h5、h7这种单调递减的序列,然后每次在后面增加一个柱子,如果我们增加的柱子比我们最后的柱子要高,就可以形成新的雨水,然后计算增加雨水的量,进行累加即可,易知应该需要用到单调栈

class Solution {
public:
    int trap(vector<int>& height) {
        stack<int> s;
        int ans = 0;
        for (int i = 0; i < height.size(); i++) {
            while (!s.empty() && height[s.top()] < height[i])
            {
                int min_h = height[s.top()];//记录弹出柱子的高度
                s.pop();
                if (s.empty()) break;
        //计算出弹出柱子两侧相邻最矮柱子的高度与弹出柱子高度差,再乘以下标差,此时就为新增雨水面积
                ans = ans + (min(height[s.top()], height[i]) - min_h) * (i - s.top() - 1); 
            }
            s.push(i);
        }
        return ans;
    }
};

四、和至少为K的最短子数组

思路:

       假设如下每个节点都代表了前缀和数组中的每一个值,假设当前已经遍历到黄色这个节点,绿色代表黄色点之前所有点的最小值,红色点代表从绿色到黄色点区间内的最小值,蓝色点则代表红色点到黄色点区间内的最小值

       此时我们需要找到黄色点前的一个点,使得黄色点需要减去那一个值,并且这个差值必须大于等于K,因此我们需要找的就是黄色点前的最小值,假如黄色点减去绿色点的差值大于等于K,但是由于我们要求最短子数组,此时绿色点就可以被抛弃,即弹出,因此我们就需要在绿色点后面找点,即红色点,如果黄色点与红色点的差值也大于等于K,那么黄色点也弹出,那我们就去找蓝色点,不断往后,即需要维护绿红蓝这三个点

        易知应该使用单调队列来解决该题,即把原数组处理为前缀和数组,然后将原数组中每一项依次性压入到单调队列中,每次压入前,需要用当前的值和单调队列的队首进行比较,若当前值减去队首元素的值大于等于K,此时队首元素就可以出队,然后再把当前元素压入单调队列

class Solution {
public:
    int shortestSubarray(vector<int>& nums, int k) {
        int n = nums.size();
        vector<long long> s(n + 1, 0);//前缀和数组
        for (int i = 1; i <= n; i++) {
            s[i] = s[i - 1] + nums[i - 1];
        }
        deque<int>q;
        q.push_back(0);
        int ans = n + 1;
        for (int i = 1; i <= n; i++) {
            while (!q.empty() && s[i] - s[q.front()] >= k) {
                ans = min(ans, i - q.front());
                q.pop_front();
            }

            while (!q.empty() && s[i] < s[q.back()]) q.pop_back();
            q.push_back(i);
        }

        if (ans == n + 1) return -1;
        return ans;
    }
};

五、双生序列

思路:

       假设已有A、B两序列,两个都固定了结尾位置r的情况下,它们的趋势相同就是从最小值到最小值后面的最小值到最小值后面的最小值的最小值的所在位置相同,然后将黄蓝绿红的位置存储在单调队列中,其趋势相同也意味着它们在单调队列所存储的元素也相同,注意在单调队列中所存储位置对应值应该是单调递增的

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <deque>
using namespace std;

int main()
{
	int n;
	cin >> n;
	vector<int> a(n + 1), b(n + 1);
	for (int i = 1; i <= n; i++) cin >> a[i];
	for (int i = 1; i <= n; i++) cin >> b[i];
	deque<int> ap, bp;
	int p; //找最大值i
	for (p = 1; p <= n; p++)
	{
		while (!ap.empty() && a[p] <= ap.back()) ap.pop_back();
		while (!bp.empty() && b[p] <= bp.back()) bp.pop_back();

		ap.push_back(a[p]);
		bp.push_back(b[p]);

		if (ap.size() != bp.size()) break; //说明到此位置结束
	}

	cout << p - 1<< endl; 
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/790447.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CV05_深度学习模块之间的缝合教学(1)

1.1 在哪里缝 测试文件&#xff1f;&#xff08;&#xff09; 训练文件&#xff1f;&#xff08;&#xff09; 模型文件&#xff1f;&#xff08;√&#xff09; 1.2 骨干网络与模块缝合 以Vision Transformer为例&#xff0c;模型文件里有很多类&#xff0c;我们只在最后…

Flutter——最详细(Table)网格、表格组件使用教程

背景 用于展示表格组件&#xff0c;可指定线宽、列宽、文字方向等属性 属性作用columnWidths列的宽度defaultVerticalAlignment网格内部组件摆放方向border网格样式修改children表格里面的组件textDirection文本排序方向 import package:flutter/material.dart;class CustomTa…

Mac 上安转文字转 SQL 利器 WrenAI

WrenAI 是一个开源的 Text-SQL 的工具&#xff0c;通过导入数据库结构&#xff0c;通过提问的方式生成 SQL。本文将讲述如何在 MacOS 上安装 WrenAI。要运行WrenAI&#xff0c;首先需要安装 Docker 桌面版。 下载 WrenAI https://github.com/Canner/WrenAI/releases/tag/0.7.…

开源流程表单设计器都有哪些值得一提的优势?

如果需要提质、增效、降本&#xff0c;不妨来了解下低代码技术平台、开源流程表单设计器的功能和优势特点。想要实现流程化办公&#xff0c;低代码技术平台是助力增效的理想工具。功能灵活、操作方便、好维修、可视化操作等优势都是其深受行业喜爱的优势特点。通过本文&#xf…

DDL也会有undo吗?模拟Oracle中DML、DDL与undo的关系,10046跟踪DDL语句

已经有两个月没有更新博客了&#xff0c;主要实在忙毕设和毕业的一些事情&#xff01;这两个月也是非常的精彩呀&#xff0c;充分体会到了职场的和校园的不同&#xff0c;作为一名刚毕业就满 1 年工作经验的牛马人&#xff0c;在两个月期间经历了两次调岗、两次降薪&#xff0c…

一句歌词描述夏天

夏天总是带着一种奇特的魔力&#xff0c;既能让人沉醉在阳光和海浪的浪漫中&#xff0c;也能在炎热与燥热中让人心生烦闷。特别是在夏日里情绪低落时&#xff0c;那些可以抚平心情的歌曲显得尤为珍贵。音乐&#xff0c;这个神奇的存在&#xff0c;总能在最需要的时候带来心灵的…

使用AutoGPT构建智能体:从LSTM到Prompt编写实战教程001

如果报错,这里会有一个环境变量的设置需要设置上. 然后这一节我们来自己制作一个智能体,来感受一下,实际上现在,大模型还是可以做很多功能的. 可以看到上面是智能体的架构,之前也说过了, 上面这几个功能,如果用我们人类去操作,还是需要花些时间的,如果用大模型就快很多了. 以…

利用Python的sympy包求解一元多次方程

一元1次方程 import sympy as sp # 导入sympy包 x sp.Symbol(x) # 定义符号变量 f 2*x -8 # 定义要求解的一元1次方程 x sp.solve(f) # 调用solve函数求解方程 x[4]一元2次方程 import sympy as sp # 导入sympy包 x sp.Symbol(x) # 定义符号变量 f …

Nature Protocols:整合多组学并进行因果推理的系统框架

转载自&#xff1a;MetaAI 在生物学研究中&#xff0c;随着实验和计算技术的进步&#xff0c;生物系统研究产生了大量高通量数据。技术努力主要集中在提高吞吐量、降低成本和提升实验与计算效率。因此&#xff0c;整合不同类型组学数据&#xff0c;并通过关联分析识别关键因素…

[机器学习]-人工智能对程序员的深远影响——案例分析

机器学习和人工智能对未来程序员的深远影响 目录 机器学习和人工智能对未来程序员的深远影响1. **自动化编码任务**1.1 代码生成1.2 自动调试1.3 测试自动化 2. **提升开发效率**2.1 智能建议2.2 项目管理 3. **改变编程范式**3.1 数据驱动开发 4. **职业发展的新机遇**4.1 AI工…

大数据开发者:如何快速熟悉新公司的技术环境

目录 1. 了解系统架构实践建议&#xff1a;示例对话&#xff1a; 2. 了解领域模型实践建议&#xff1a;示例&#xff1a; 3. 了解代码结构实践建议&#xff1a;示例&#xff1a; 结语 作为一名大数据开发者&#xff0c;加入新公司后快速熟悉技术环境是一项重要而又具有挑战性的…

bev 之 fastBEV

前面我们提到bev 之 LSS, 知道视觉的BEV方案的主要痛点在于: 1、depth 的预测 2、图像特征到BEV特征之间的视图变换消耗大量计算 LSS 为什么需要D维深度 占据大量消耗的原因是LSS 对每个图像特征点引入深度D&#xff0c;即假设每个像素上存在可能的D维深度。也就是假设不同像…

C++ 栈-队列-优先级队列

目录 1 栈 2 队列 3 deque 介绍 4 优先级队列 5 反向迭代器 栈也是我们在C语言就模拟实现过的一种数据结构&#xff0c;在C中&#xff0c;栈其实和我们前面模拟实现过的string、vector等容器有一点区别&#xff0c;站起是不是容器&#xff0c;而是一种容器适配器&#xff0c;我…

Floyd判圈算法——寻找重复数(C++)

287. 寻找重复数 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给定一个包含 n 1 个整数的数组 nums &#xff0c;其数字都在 [1, n] 范围内&#xff08;包括 1 和 n&#xff09;&#xff0c;可知至少存在一个重复的整数。假设 nums 只有 一个重复的整数 &#xff0c;返…

python基础语法笔记(有C语言基础之后)

input()用于输入&#xff0c;其有返回值&#xff08;即用户输入的值&#xff09;&#xff0c;默认返回字符串。括号里可放提示语句 一行代码若想分为多行来写&#xff0c;需要在每一行的末尾加上“\” 单个“/”表示数学中的除法&#xff0c;不会取整。“//”才会向下取整。 …

无人机之飞行规划与管理篇

无人机飞行规划与管理是确保无人机安全、高效且符合法规的运行的关键步骤。这一过程包括了对飞行任务的详细安排、航线的设定以及风险的评估和管理。下面简述这一过程的主要环节&#xff1a; 一、飞行目的和任务确定 在规划之初&#xff0c;必须明确无人机的飞行目的&#xf…

HTTPS理解

一个完整的HTTP连接 TCP三次握手接受窗口发送数据关闭连接 接受窗口是用来做什么呢&#xff1f; 它根据自身网络情况设置不同大小的值用来控制对方发送速度&#xff0c;避免对方发送太快&#xff0c;导致网络拥塞。 为什么TCP握手要三次&#xff1f; 1&#xff09;确认双方的…

单片机中有FLASH为啥还需要EEROM?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「单片机的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 一是EEPROM操作简单&…

JDK11中zgc垃圾回收器的探索

背景 垃圾回收器主要做的事情 自动跟踪和管理程序中创建的对象&#xff0c;确定哪些对象仍在使用&#xff0c;哪些对象已经不再使用。回收那些不再使用的对象所占用的内存空间&#xff0c;使得这部分内存可以被重新使用。 1.1 传统垃圾回收器 垃圾回收器简述优缺点应用场景…

typora 两边太宽,设置宽度

步骤&#xff1a; 查看目前使用主题类型 文件 —> 偏好设置 —> 外观 —> 打开主题文件夹 修改对应的主题&#xff1a;max-width