单调队列详解

单调队列详解刚学单调队列时,在网上各大博客找文章学,说实话,写得很杂,表示自己懵逼了些许,最后硬是啃出来了,所以我决定要写一篇能让大部分人都看懂的博客来。说单调队列,那我们就先说说这个单调队列是个什么物种。单调队列从字面上看,无非就是有某种单调性的队列,没错,这就是所谓的单调队列。单调队列它分两种,一种是单调递增的,另外一种是单调递减的。在这搬出百度百科的解释:不断地向缓存数组里读入元素,也不时地去掉最老的…

大家好,又见面了,我是你们的朋友全栈君。

刚学单调队列时,在网上各大博客找文章学,说实话,写得很杂,表示自己懵逼了些许,最后硬是啃出来了,所以我决定要写一篇能让大部分人都看懂的博客来。


说单调队列,那我们就先说说这个单调队列是个什么物种。单调队列从字面上看,无非就是有某种单调性的队列,没错,这就是所谓的单调队列。 单调队列它分两种,一种是单调递增的,另外一种是单调递减的。

在这搬出百度百科的解释:不断地向缓存数组里读入元素,也不时地去掉最老的元素,不定期的询问当前缓存数组里的最小的元素。

用单调队列来解决问题,一般都是需要得到当前的某个范围内的最小值或最大值。


举个例子:有  7 6 8 12 9 10 3 七个数字,现在让你找出范围( i-4,i ) 的最小值。

那我们就可以这样模拟一遍。

先初始化{ 0 } (表示i=0时的值)

i=1 ->{ 0 } (表示i=1,时,在其范围内最小的值为0)-> 7进队 { 7 }

i=2->{ 7 }表示i=2,时,在其范围内最小的值为7)-> 6比7小,7出,6进 { 6 }

i=3-> { 6 } (表示i=3,时,在其范围内最小的值为6)->8比6大,8进  { 6, 8}

i=4->{ 6, 8}(表示i=4,时,在其范围内最小的值为6)-> 12比8大,12进 {6, 8 , 12};

i=5-> {6, 8 , 12}表示i=4,时,在其范围内最小的值为6)-> 9比12小,12out,9比8大,9进 {6,8,  9}

i=6-> {6,8,  9} 但是 单调队列中元素6的下标是2,不在(2, 6],中,故6 out,这就是单调队列的精髓了。故单调队列为

{ 8,9 }(表示i=5,时,在其范围内最小的值为8)->10比9大,10进 最终 单调队列为{ 8,9, 10} ;

i=7->{ 8,9, 10}(表示i=6,时,在其范围内最小的值为8)-> 3比单调队列为{ 8,9, 10} 的任意值都小,故全out,最终集合为 { 3 }


相信大家看完这个例子了解得有些吧,再次重申一遍,单调队列的核心(我认为的哈):得到当前的某个范围内的最小值或最大值。要不是这样的话,那还有必要这么麻烦找吗,直接找前面最小的就好了,可事实不是这样,题目是有限制的,规定在某个范围内找。

那我们就来看到例题,加深理解:


最大子序和

  • Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Others)
  • Total Submission(s): 9     Accepted Submission(s): 2
Description

一个长度为n的整数序列,从中找出一段不超过m的连续子序列,使得整个序列的和最大。

例如:  1, -3, 5, 1, -2, 3

当m=4时,sum =  5+1-2+3 = 7

当m=2或m=3时,sum = 5+1 = 6

Input

多测试用例,每个测试用例:

第一行是两个正数n, m  ( n, m ≤ 300000 )

第二行是n个整数

Output

每个测试用例输出一行:一个正整数,表示这n个数的最大子序和长度

Sample Input

6 4
1 -3 5 1 -2 3

Sample Output

7


这题可以用dp来解,在这我们就用单调队列来解。

我们先把序列的前i项和加起来并存到一个数组sum[ ]上,那么任意连续的子序列和就为sum [ i ] – sum[ j ] (i>j &&  j>i-m)。

那么我们就可以跟上述例子一样,一直更新就好了,每次找出在(i-m,i)范围内的最小sum[j]

代码一:

#include<cstdio> #include<algorithm>///单调队列, #include<cstring> #include<list> using namespace std; typedef long long LL; const int maxn=300010; LL sum[maxn]; list <int > que; int main() { int n,m; while(~scanf("%d%d",&n,&m)) { que.clear(); ///清除 sum[0]=0; for(int i=1;i<=n;i++) { scanf("%lld",&sum[i]); sum[i]=sum[i-1]+sum[i]; ///求前i项和 } ///初始化 LL maxs=sum[1]; que.push_front(1); for(int i=2;i<=n;i++) { while(!que.empty()&&i-que.back()>m) ///此步是判断是否在范围(i-m,i)内,不在就pop que.pop_back(); maxs=max(maxs,sum[i]-sum[que.back()]); ///求最大值,sum[i]-sum[min],表示前i个中找到最小的来减,sum[min]就是单调队列的尾部sum[que.back()] while(!que.empty()&&sum[i]<sum[que.front()]) ///更新单调队列,比sum[i]大的值都去掉 que.pop_front(); que.push_front(i); ///最后将下标i入队 } printf("%lld\n",maxs); } return 8; } 

代码二:

#include<cstdio> ///单调递增序列(但保证最可能小) #include<algorithm> #include<cstring> using namespace std; typedef long long LL; const LL maxn=300010; LL sum[maxn]; LL index1[maxn]; ///存储下标 int main() { LL n,m; while(~scanf("%lld%lld",&n,&m)) { sum[0]=0; for(int i=1;i<=n;i++){ scanf("%lld",&sum[i]); sum[i]+=sum[i-1]; ///求前i项和 } ///初始化 int left=1,right=1; index1[1]=1; LL tmax=sum[1]; for(int i=2;i<=n;i++) { while(index1[left]<i-m) left++; ///不在范围(i-m,i)内,左移就好了 tmax=max(tmax,sum[i]-sum[index1[left]]); ///减去范围(i-m,i)内最小的值 while(right>=left&&sum[i]<sum[index1[right]]) ///排除比值sum[i]大的 right--; right++; index1[right]=i; ///将下标添加进去 } printf("%lld\n",tmax); } return 0; }


我的标签:做个有情怀的程序员!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/152974.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Eureka集群(Eureka详解)

    Eureka集群(Eureka详解)前言上篇文章,我们已经搭建了微服务的框架,使用了SOA(服务治理)Eureka参考:Eureka注册中心这篇文章教大家,如何使用IDEA搭建SpringCloud的集群,Spring拥有最简单的搭建集群方法一、使用IDEA二、配置写上你配置的名字,01,02区分就好,以及要集群那个模块三、端口号-Dserver.port=10087-D是修改,必须写…

    2022年5月5日
    60
  • CompoundButton 源码分析

    CompoundButton 源码分析原文地址:https://github.com/Tikitoo/AndroidSdkSourceAnalysis/blob/master/article/CompoundButton%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90.md CompoundButton是一个有两种状态(选中和未选中/checkdunchecked)的Button。当你按下(pres…

    2022年6月7日
    34
  • PostGIS 报错libcrypto[通俗易懂]

    PostGIS 报错libcrypto[通俗易懂]说明在安装完Postgresql以后,打postgis扩展时,报错ERROR:couldnotloadlibrary”/usr/pgsql-12/lib/rtpostgis.so”:/usr/pgsql-12/lib/libpq.so.10:symbolX509_get_signature_nid,versionlibcrypto.so.10notdefinedinfilelibcrypto.so.10withlinktimereference出现问题环境

    2022年6月26日
    58
  • gis如何无缝拼接两张图_arcgis多幅影像图拼接

    gis如何无缝拼接两张图_arcgis多幅影像图拼接APAP.cpp#include”stdafx.h”#include<iostream>#include<cmath>#include”opencv2/features2d/features2d.hpp”#include”opencv2/highgui/highgui.hpp”#include”opencv2/opencv_modules.hpp”#include”opencv2/calib3d/calib3d.hpp”#include..

    2022年9月22日
    2
  • List转JSONArray和JSONArray转List转

    List转JSONArray和JSONArray转List转@List转JSONArray和JSONArray转List1.List转JSONArrayListlist=newArrayList();JSONArrayarray=JSONArray.parseArray(JSON.toJSONString(list));2.JSONArray转ListJSONArrayarray=newJSONArray();Listli…

    2022年6月16日
    31
  • icem二维非结构网格划分_Ansys Icem CFD网格划分实例详解PDF及附件[通俗易懂]

    icem二维非结构网格划分_Ansys Icem CFD网格划分实例详解PDF及附件[通俗易懂]网格划分是CFD仿真计算中重要的一环,icem也是Ansys家族的王牌成员,虽然现在已被mesh以及fluentmesh追赶,但是依旧是学生时代主流的追求完美结构化网格的利器!学好icem对于拓结构的理解也会更深刻!这本书没找到原版的,只有影印版,看起来不是很舒服,但是有配套视频可以学习,也算慰藉。建议买本纸质版康康,虽然纸质版也不是很清晰,因为不是彩印的,所以凑活看吧!一、书籍简介名…

    2022年5月26日
    47

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号