单调队列总结

本文详细介绍了滑动窗口算法在不同问题中的应用,包括求解区间最值问题、连续子序列和的最大值以及满足特定条件的断开点数量。通过具体实例展示了如何使用单调队列进行高效计算。

poj 2823     N个数,每个区间从左到右选取K个数,求每个区间中的最小值,最大值

void  GetMin(){ //保持队列严格单调递增
      int i , j  ;
      int head = 0 , tail = -1 ;
      for(i = 1 ; i <= n ; i++){
           while(head <= tail && a[que[tail]] >= a[i]) tail-- ;
           que[++tail] = i ;
           while(que[tail] - que[head] + 1 > k) head++ ;
           if(i == k) printf("%d" , a[que[head]]) ;
           else if(i > k) printf(" %d" ,a[que[head]]) ;
      }
      puts("") ;
}

void  GetMax(){ //保持队列严格单调递减
      int i , j  ;
      int head = 0 , tail = -1 ;
      for(i = 1 ; i <= n ; i++){
           while(head <= tail && a[que[tail]] <= a[i]) tail-- ;
           que[++tail] = i ;
           while(que[tail] - que[head] +1 > k) head++ ;
           if(i == k) printf("%d" , a[que[head]]) ;
           else if(i > k) printf(" %d" ,a[que[head]]) ;
      }
      puts("") ;
}



HDU 3415   长度为N的环状序列,求长度<=K的的连续子序列的和,使得和最大

   sum[i] = a[1] + a[2] + .....+ s[i] .
   a[i]   =  sum[i]  - sum[i-1] ;
   a[i] + a[i-1] = sum[i] - sum[i-2] ;
   .......
   a[i] + a[i-1] + .....+ s[i-k+1] = sum[i] - sum[i-k] ; 
如果序列以i 结束,  则和为  sum[i] -  min{ j | sum[j] }   (i-k <= j <=  i-1) 。
void  Ans(){
      int i , j  , head = 0 , tail = -1 , ans = -(1<<30) , L , R ;
      sum[0] = 0  ;
      for(i = 1 ; i <= n ; i++)  sum[i] = sum[i-1] + a[i] ;
      for(i = n+1 ; i < n+k ; i++) sum[i] = sum[i-1] + a[i-n] ;
      int m = n + k - 1 ;
      for(int i = 1 ; i <= m ; i++){
           while(head <= tail && sum[que[tail]] >= sum[i-1])  tail-- ; //单调递增
           que[++tail] = i-1 ;
           while(que[head] < i-k) head++ ;
           if(ans < sum[i] -  sum[que[head]]){
                 ans = sum[i] - sum[que[head]] ;
                 L = que[head] + 1 ;
                 R = i ;
           }
      }
      if(L > n) L -= n ;
      if(R > n) R -= n ;
      printf("%d %d %d\n" , ans , L , R) ;
}

HDU 3474  长度为n的项链,珠子为C,J。从某处断开,从断开处往左数或者往右数,到每个点的C个数>=J个数,求断开点的总数


     C = 1 , J = -1 ,维护前缀和。
     1 2 3 4 5 6 7 8 1 2 3  4 5 6 7 8
     [1->8 ]  区间min{sum} >= sum[0] 满足
     [2->8->1]   区间min{sum} >= sum[1] 满足
     [3->8->2]   区间min{sum} >= sum[2] 满足
     .......
  sum 【i-n+1 ,i】最小值 >= sum[i-n] 满足。 
注意这个顺序是顺着数。 dp0[0]  =  [1->8] ,  dp0[1] = [2->8>1] 。
倒着数把串逆序。8 7 6 5 4 3 2 1 8 7 6 5 4 3 2 1  dp1[0] = [8->1] ,  dp1[1] = [7->1->8] 。
                 从8 ,1 处断开。 顺【1->8】<=> dp1[0] ,逆【8->1】<=> dp2[8] 。               
 
const int  Max_N = 1000008 ;
char str[Max_N] ;
int  sum[Max_N*2] , que[Max_N*2] ;
int  n  ;

void  Solve(bool dp[]){
      int i , j  , m = n + n  , head = 0  , tail = -1 ;
      sum[0] = 0 ;
      for(i = 1 ; i <= n ; i++) sum[i] = sum[i-1] + (str[i] == 'C' ? 1 : -1) ;
      for(i = n+1 ; i <= m ; i++) sum[i] = sum[i-1] + (str[i-n] == 'C' ? 1: -1) ;
      for(i = 1 ; i < n ; i++){
           while(head <= tail && sum[que[tail]] >= sum[i]) tail-- ;
           que[++tail] = i ;
      }
      for(i = n ; i <= m ; i++){
           while(head <= tail && sum[que[tail]] >= sum[i]) tail-- ;
           que[++tail] = i ;
           while(head <= tail && que[head] <= i - n) head++ ;
           if(sum[que[head]] >= sum[i-n])
              dp[i-n] = 1 ;
      }
}

bool dp[2][Max_N] ;

int  main(){
     int t  , ans , i , T = 1 ;
     cin>>t  ;
     while(t--){
          scanf("%s" ,str+1) ;
          n = strlen(str+1) ;
          memset(dp , 0 , sizeof(dp)) ;
          Solve(dp[0]) ;
          std::reverse(str+1 , str+1+n) ;
          Solve(dp[1]) ;
          ans = 0 ;
          for(i = 0 ; i < n ; i++)  ans += (dp[0][i] | dp[1][n-i]) ;
          printf("Case %d: %d\n" ,T++ , ans) ;
     }
     return  0 ;
}

   





标题基于SpringBoot的马术俱乐部管理系统设计与实现AI更换标题第1章引言介绍马术俱乐部管理系统的研究背景、意义、国内外研究现状、论文方法及创新点。1.1研究背景与意义阐述马术俱乐部管理系统对提升俱乐部管理效率的重要性。1.2国内外研究现状分析国内外马术俱乐部管理系统的发展现状及存在的问题。1.3研究方法以及创新点概述本文采用的研究方法,包括SpringBoot框架的应用,以及系统的创新点。第2章相关理论总结和评述与马术俱乐部管理系统相关的现有理论。2.1SpringBoot框架理论介绍SpringBoot框架的基本原理、特点及其在Web开发中的应用。2.2数据库设计理论阐述数据库设计的基本原则、方法以及在管理系统中的应用。2.3马术俱乐部管理理论概述马术俱乐部管理的基本理论,包括会员管理、课程安排等。第3章系统设计详细描述马术俱乐部管理系统的设计方案,包括架构设计、功能模块设计等。3.1系统架构设计给出系统的整体架构,包括前端、后端和数据库的交互方式。3.2功能模块设计详细介绍系统的各个功能模块,如会员管理、课程管理、预约管理等。3.3数据库设计阐述数据库的设计方案,包括表结构、字段设计以及数据关系。第4章系统实现介绍马术俱乐部管理系统的实现过程,包括开发环境、编码实现等。4.1开发环境搭建介绍系统开发所需的环境,包括操作系统、开发工具等。4.2编码实现详细介绍系统各个功能模块的编码实现过程。4.3系统测试与调试阐述系统的测试方法、测试用例以及调试过程。第5章系统应用与分析呈现马术俱乐部管理系统的应用效果,并进行性能分析。5.1系统应用情况介绍系统在马术俱乐部中的实际应用情况。5.2系统性能分析从响应时间、并发处理能力等方面对系统性能进行分析。5.3用户反馈与改进收集用户反馈,提出系统改进建议。第6章结论与展望总结马术俱乐部管理系统的设计与实现成果,并展望未来的研究
### 单调队列与单调栈的原理、区别及应用场景 #### 一、单调栈的原理 单调栈是一种特殊的栈结构,其核心特点是栈内的元素保持单调性(递增或递减)。在实际应用中,当新元素入栈时,会从栈顶开始移除所有破坏单调性的元素,然后将新元素压入栈中。这种特性使得单调栈特别适合解决“Next Greater Element”类问题,即找到每个元素右侧第一个比它大的元素[^1]。 ```python def next_greater_element(nums): stack = [] result = [-1] * len(nums) # 初始化结果数组 for i in range(len(nums)): while stack and nums[stack[-1]] < nums[i]: idx = stack.pop() result[idx] = nums[i] stack.append(i) return result ``` #### 二、单调队列的原理 单调队列是一种特殊的队列结构,其核心特点是队列内的元素保持单调性(递增或递减)。在实际应用中,当新元素入队时,会从队尾开始移除所有破坏单调性的元素,然后将新元素加入队尾。同时,当滑动窗口移动时,需要从队首移除那些已经不在当前窗口范围内的元素[^4]。这种特性使得单调队列特别适合解决滑动窗口最大值或最小值问题。 ```python from collections import deque def sliding_window_maximum(nums, k): queue = deque() result = [] for i in range(len(nums)): while queue and nums[queue[-1]] <= nums[i]: queue.pop() queue.append(i) if queue[0] <= i - k: queue.popleft() if i >= k - 1: result.append(nums[queue[0]]) return result ``` #### 三、单调栈与单调队列的区别 1. **数据结构类型**:单调栈是基于后进先出(LIFO)的数据结构,而单调队列是基于先进先出(FIFO)的数据结构。 2. **操作顺序**:单调栈的操作主要发生在栈顶,而单调队列的操作既涉及队首(移除过期元素),也涉及队尾(维护单调性)。 3. **适用场景**:单调栈适用于解决“Next Greater Element”类问题,而单调队列适用于解决滑动窗口最大值或最小值问题[^2]。 #### 四、应用场景 - **单调栈的应用场景**: - 寻找数组中每个元素右侧第一个比它大或小的元素[^1]。 - 计算直方图中最大的矩形面积[^2]。 - **单调队列的应用场景**: - 求解滑动窗口内的最大值或最小值[^3]。 - 时间序列的范围查询[^3]。 #### 五、总结 单调栈和单调队列都是高效的算法工具,能够显著降低时间复杂度。选择使用哪种结构取决于具体问题的需求。如果问题是关于元素间有序性的问题,如“Next Greater Element”,则优先考虑单调栈;如果问题是关于滑动窗口的最大值或最小值,则优先考虑单调队列。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值