蓝桥杯每日一题----单调栈和单调队列

单调栈和单调队列

单调栈

单调栈即栈内的元素是单调递减或者单调递增的,我们通过一个题目来理解。

单调栈模板题

题目描述

给出项数为 n 的整数数列 a 1 … a n a_1…a_n a1an

定义函数 f ( i ) f(i) f(i)代表数列中第 i 个元素之后第一个大于 a i a_i ai 的元素的下标,即 f ( i ) = m i n i < j < = n , a j > a i j f(i)=min_{i<j<=n,a_j>a_i}{j} f(i)=mini<j<=n,aj>aij。若不存在,则 f ( i ) = 0 f(i)=0 f(i)=0

试求出 f ( 1 … n ) f(1…n) f(1n)

输入格式

第一行一个正整数 n

第二行 n 个正整数 a 1 … a n a_1…a_n a1an

输出格式

一行n个整数表示 f ( 1 ) , f ( 2 ) , … , f ( n ) f(1),f(2),…,f(n) f(1),f(2),,f(n)的值。

题目分析

题目要求第i个数后面第一个比 a [ i ] a[i] a[i]大的数。首先从头遍历数组,将第一个元素入栈,接着遍历下一个元素,假设当前入栈的元素下标为i,当前遍历到了 i + 1 i+1 i+1,如果 a [ i ] > a [ i + 1 ] a[i]>a[i+1] a[i]>a[i+1],那么 a [ i + 1 ] a[i+1] a[i+1]就不入栈接着向后遍历,如果 a [ i ] < a i + 1 a[i]<ai+1 a[i]<ai+1,那么 a [ i + 1 ] a[i+1] a[i+1]入栈,也就是说栈中的元素是单调递增的。入栈入的是数组的下标,那么在遍历数组的过程中第 i i i个数后面第一个比 a [ i ] a[i] a[i]大的数也就是遍历到 i i i后,后面第一个入栈的元素对应的值。但是什么时候会有第一个元素入栈,这个不好判断。

换个思路,假设我们是找 i i i左边第一个比 i i i小的数字,从头开始遍历数组,将第一个元素入栈,接着遍历下一个元素,假设当前入栈的元素下标为 i i i,当前遍历到了 i + 1 i+1 i+1,如果 a [ i + 1 ] > = a [ i ] a[i+1]>=a[i] a[i+1]>=a[i],则将 a [ i ] a[i] a[i]从栈中弹出,因为 a [ i + 1 ] a[i+1] a[i+1] a [ i ] a[i] a[i]的右边,对于求左边第一个比 a [ i + 2 ] a[i+2] a[i+2]大的数字,如果 a [ i ] > a [ i + 2 ] a[i]>a[i+2] a[i]>a[i+2],必然会有 a [ i + 1 ] > a [ i + 2 ] a[i+1]>a[i+2] a[i+1]>a[i+2],而 a [ i + 1 ] a[i+1] a[i+1]从左边更靠近 a [ i + 2 ] a[i+2] a[i+2],所以它会成为答案,也就是只要 a [ i + 1 ] a[i+1] a[i+1]在这里, a [ i ] a[i] a[i]永远不会成为答案,所以直接弹出就行了。那么最后栈顶的元素要么为空要么大于 a [ i + 1 ] a[i+1] a[i+1],并且是从 a [ i + 1 ] a[i+1] a[i+1]往左数第一个大于 a [ i + 1 ] a[i+1] a[i+1]的数字,所以栈顶元素即为我们想要的答案。

上述思路用一个图来表示,1,2,3,4,5表示的是数组下标,矩形的高度表示的是数组中值的大小,值越大,矩形越高。

当遍历到3的时候,2比3小,所以要从栈里面弹出,后续遍历到4,即便2要比4大,但是因为3的存在只要2符合条件3一定符合条件,但是3要比2更靠近4,也就是更靠近后面的数,所以3永远不会成为答案,把3弹出栈没有问题。遍历到5的时候,虽然3要比4大,也比5大,但是4比5大且更靠近5,所以4是答案。而如果5大于4小于3时,3又会成为答案,所以此时无论是4还是3都有可能成为答案,所以他们留在栈中。

换个形象点的方式,就是站在4上向左看,比3小的数字一定会被3挡住,所以从栈中拿掉就可以了,比如站在4中向左看,只能看到1和3,此时栈中也就只剩下了1和3。站在5中向左看,可以看见1,3,4。

刚刚讲的是求一个数字左边第一小的数字,但是题目要求的是右边第一小的数字,那么只需要对原数组倒序遍历就是求左边第一小的数字了。

题目代码

package 单调队列和单调栈;
import java.util.Scanner;
import java.util.Stack;
public class 单调栈模板 {
public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int a[] = new int[n+1];int f[] = new int[n+1];for(int i = 1;i <= n;i++) a[i] = scanner.nextInt();Stack<Integer> stack = new Stack<Integer>();for(int i = n;i > 0;i--) {while(!stack.isEmpty()&&a[stack.peek()]<=a[i]) stack.pop();if(!stack.isEmpty())f[i] = stack.peek();stack.push(i);}for(int i = 1;i <= n;i++)System.out.print(f[i] + " ");
}
}

ps:感觉洛谷对非c++不太友好,很容易超时或者超内存,这个代码就有几个样例超内存了。

单调队列实现滑动窗口

单调栈值从栈顶弹元素和进元素,单调队列从队头弹元素,从队尾进元素。

单调队列模板

题目描述

有一个长为 n 的序列 a,以及一个大小为 k 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。

例如,对于序列 [ 1 , 3 , − 1 , − 3 , 5 , 3 , 6 , 7 ] [1,3,−1,−3,5,3,6,7] [1,3,1,3,5,3,6,7]以及 k=3,有如下过程:

输入格式

输入一共有两行,第一行有两个正整数 n,k。 第二行 n 个整数,表示序列 a

输出格式

输出共两行,第一行为每次窗口滑动的最小值
第二行为每次窗口滑动的最大值

题目分析

用队列来模拟一下滑动窗口的过程。两个判断

第一个判断是否还在窗口内,因为随着窗口的滑动必然会有一些数字已经离开了窗口,这个时候就要从队列里面删掉。

第二个判断是否有无效数字。对于求最大值的队列来说,假设窗口内的数字是[1,2,1],那么第一个数字1可以提早删掉,因为此时的2是窗口内的最大值并且只要第一个1没有被移出窗口那么2必然也还在,也就是第一个1受2的“压制”永远不会成为窗口内的最大值,直接删掉就可以了。变成了[2,1],那么此时剩下的这个1需要删掉吗?不能删掉,因为数字2会比1先离开窗口,当2离开窗口后,1仍然有机会成为最大值。也就是说这里存的应该是一个单调递减序列,当前待入队数字比队尾数字大,队尾数字就出队。

那么最大值在哪?单调递减序列,最大值自然是第一个数字也就是队头元素。

同样队列里面存的是数组的下标,因为我可以通过数组下标快速判断数字是否还在窗口内,假设当前数字下标为5,窗口大小为3,那么下标小于等于5-3=2的直接出队。

求最小值也是同样的分析方式。

题目代码

package 单调队列和单调栈;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Scanner;public class 单调队列模板 {
public static void main(String[] args) throws IOException {Scanner scanner = new Scanner(System.in);BufferedReader br = new BufferedReader(new InputStreamReader(System.in));String[] strings = br.readLine().split(" ");int n = Integer.parseInt(strings[0]);int k = Integer.parseInt(strings[1]);int a[] = new int[n+1];int max[] = new int[n+1];int min[] = new int[n+1];strings = br.readLine().split(" ");for(int i = 1;i <= n;i++) a[i] = Integer.parseInt(strings[i-1]);Deque<Integer> qDeque = new ArrayDeque<Integer>();for(int i = 1;i <= n;i++) {while(!qDeque.isEmpty()&&i-qDeque.peekFirst()>=k) {qDeque.pollFirst();}while(!qDeque.isEmpty()&&a[qDeque.peekLast()]<=a[i]) {qDeque.pollLast();}qDeque.addLast(i);max[i] = a[qDeque.peekFirst()];}qDeque.clear();for(int i = 1;i <= n;i++) {while(!qDeque.isEmpty()&&i-qDeque.peekFirst()>=k) qDeque.pollFirst();while(!qDeque.isEmpty()&&a[qDeque.peekLast()]>=a[i]) qDeque.pollLast();qDeque.addLast(i);if(i>=k)min[i] = a[qDeque.peekFirst()];}for(int i = k;i <= n;i++)System.out.print(min[i] + " ");System.out.println();for(int i = k;i <= n;i++)System.out.print(max[i] + " ");
}
}

ps:洛谷提交会超时

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

核心篇-OSPF技术之序(下)

文章目录 一. 实验专题1.1. 实验1&#xff1a;配置OSPF特殊区域1.1.1. 实验目的1.1.2. 实验拓扑图1.1.3. 实验步骤&#xff08;1&#xff09;配置IP地址&#xff08;2&#xff09;创建环回口&#xff08;3&#xff09;查看路由表&#xff08;4&#xff09;设置Stub区域&#xf…

linux 安装docker

目录 环境 操作步骤 1 下载脚本 2 执行脚本 3 检查docker版本&#xff0c;证明安装成功 环境 阿里云 ubuntu 22.04 64位 操作步骤 参考linux系统安装docker-腾讯云开发者社区-腾讯云 (tencent.com) 1 下载脚本 curl -fsSL https://get.docker.com -o get-docker.sh …

如何使用六图一表七种武器

六图一表七种武器用于质量管理&#xff1a; 描述当遇到问题时应该用那张图来解决&#xff1a; 一、如果题目说出了质量问题需要找原因&#xff1f; 解&#xff1a;用因果图&#xff0c;因果图也称石川图或鱼骨图 二、如果要判断过程是否稳定受控&#xff1f; 解&#xff1a…

Kotlin基本语法3集合

1.List集合 1.1 只读List fun main() {val list listOf("Jason", "Jack", "Jacky")println(list.getOrElse(3){"Unknown"})println(list.getOrNull(3)?:"Unknown") } 1.2 可变List fun main() {val mutableList mutabl…

幻兽帕鲁服务器如何设置定时清理内存?内存优化(设置Swap、虚拟内存)

幻兽帕鲁服务器可以通过设置定时重启游戏&#xff0c;来达到定时清理内存的目的。也可以通过安装定时清理内存的软件&#xff0c;来设置。还可以通过设置虚拟内存来设置。设置的方法如下&#xff1a; 1、腾讯云一键部署幻兽帕鲁&#xff0c;部署好之后&#xff0c;只需要在控制…

2024 CKS 题库 | 6、创建 Secret

不等更新题库 CKS 题库 6、创建 Secret Task 在 namespace istio-system 中获取名为 db1-test 的现有 secret 的内容 将 username 字段存储在名为 /cks/sec/user.txt 的文件中&#xff0c;并将password 字段存储在名为 /cks/sec/pass.txt 的文件中。 注意&#xff1a;你必须创…

C++集群聊天服务器 muduo+nginx+redis+mysql数据库连接池 笔记 (下)

C集群聊天服务器 网络模块业务模块CMake构建项目 笔记 &#xff08;上&#xff09;-CSDN博客https://blog.csdn.net/weixin_41987016/article/details/135991635?spm1001.2014.3001.5501C集群聊天服务器 数据模块业务模块CMake构建项目 笔记 &#xff08;上&#xff09;-CSDN博…

Java双非无实习秋招进大厂历程

从转后端到拿到Offer,约一年半。 背景介绍 进了快手(如果你觉得不是大厂那就不是!)&#xff1a; 真双非本科: 安徽某双非无实习: 因为编程语言问题,去过之后发现不喜欢,几天跑路!(某小厂,2023.8)竞赛水: 大创(做的安卓软件)起到一个外观上的作用吧...2022.3 大二下转的后端: …

leetcode 160 相交链表

题目 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数返回结…

Spring 事务原理总结四

作为一名认知有限的中国人&#xff0c;我对年的喜爱&#xff0c;胜过其他一切&#xff0c;因为它给了我拒绝一切的合理理由。每到这个时候&#xff0c;我都会用各种理由来为自己的不作为开脱&#xff0c;今年亦是如此。看着频频发出警报的假期余额&#xff0c;我内心的焦躁变得…

计算机网络——多媒体网络

前些天发现了一个巨牛的人工智能学习网站 通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff0c; 跳转到网站 小程一言 我的计算机网络专栏&#xff0c;是自己在计算机网络学习过程中的学习笔记与心得&#xff0c;在参考相关教材&#xff0c;网络搜素…

Learn LaTeX 020 - LaTex Math Space Font 数学排版之空格、字号、字体

数学排版中很好的处理空格、字号和字体可以使你的出版文档平添更多的特色。 这个视频介绍并演示了这些方面的相关配置。 https://www.ixigua.com/7298100920137548288?id7307759620737466891&logTagb138f9145ce004f6b52a