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

表现良好的最长时段[前缀和思想子数组]

前缀和与最长子数组

  • 前言
  • 一、表现良好的最长时间段
  • 二、前缀和思想&子数组
    • 1、前缀和&map
    • 2、前缀和&单调栈
  • 总结
  • 参考文献

前言

对于子数组/子串问题,紧密连续前缀和/滑动窗口/单调栈;挖掘内在规律,可以简化代码,降低时空复杂度或消耗量。

一、表现良好的最长时间段

在这里插入图片描述

二、前缀和思想&子数组

1、前缀和&map

抽象一下工作时长,工作时长不重要,重要的是两种类型,用1/-1标记两种类型,问题就转换成了求和为正数的最长子数组。
采用前缀和思想,用map记录前面前缀和,重复的只记最前面(为了最长子数组),为了让和为正数,当sum < 0时,查阅map中是否存在(sum - 1)即可。

class Solution {public int longestWPI(int[] hours) {// 由于只有1和-1,不可能前缀和出现跳跃的情况,所有hashMap就可以处理。// TreeMap<Integer,Integer> tm = new TreeMap<>();Map<Integer,Integer> fx = new HashMap<>();for(int i = 0;i < hours.length;i++){hours[i] = hours[i] > 8 ? 1:-1;}int sum = 0;int max = 0;for(int i = 0;i < hours.length;i++){sum += hours[i];// 记录最大长度if(sum > 0) max = i + 1;else if(fx.containsKey(sum - 1)){max = Math.max(max,-fx.get(sum - 1) + i);}// 为了最长子数组,只记录最前面的前缀和。if(!fx.containsKey(sum)) fx.put(sum,i);}return max;}
}
// 总结:对于连续子数组问题,多半前缀和/滑动窗口/单调栈
// 1-如何确定连续时间段?两层for循环暴力确定?以结果向导的前缀和确定!!!
// 2-如何确定该连续时间段有效?根据map中记录的前缀和确定。

2、前缀和&单调栈

前缀和子数组[l , r]有如下特点,
当prfix[r] > prefix[l]时,则该子数组是有效数组,当prefix[l1] < prefix[l2],那么l2作为左边界是无意义的,毕竟l2可以,则l1也可以,而且还更长,所以记录一下单调减序列即可。
注:这里的单调栈和传统的单调栈不同,不是整个数组的单调栈,没有出栈操作。
再反向遍历前缀和数组,和栈中元素比较,不断出栈寻找prefix[r] > min(prefix[l]),再记录最长数组长度。
这里出栈元素是对接下来的r没有影响的,证明如下,
当r1 > r 2时,则l1 > l2,两个数组存在包含关系,没有影响。
当r1 < r2时,则l1 < l2,按照单调栈规则,l1一定在l2上面,所以出栈l1是没任何影响的。

// 单调栈
func longestWPI(hours []int) int {// 问题转换,求和大于0的最长子数组;updateHours(hours)// 记录前缀和prefix := recordPrefix(hours)// 得到单调减栈stack,top := getStack(prefix)//fmt.Println(prefix)//fmt.Println(stack)// 寻找最大子数组i := len(prefix) - 1m := 0for ; i > 0;i-- {// 剪枝,一旦prefix>0,即前面的子数组最大良好就是本身。if prefix[i] > 0 {return max(m,i)}k := ifor ; top > 0 && prefix[stack[top - 1]] < prefix[i] ; {top--k = stack[top]}m = max(m,i - k)}return m
} 
func getStack(prefix []int)([]int,int){stack := make([]int,0)top := 0for i := 1;i < len(prefix);i++ {if top == 0 || prefix[stack[top - 1]] > prefix[i] {stack = append(stack[:top],i)top++} }return stack,top
}
func recordPrefix(hours []int)[]int{prefix := make([]int,len(hours) + 1)for i,h := range hours {prefix[i + 1] = prefix[i] + h }return prefix
}
func updateHours(hours []int) {for i := 0;i < len(hours);i++ {if hours[i] > 8 {hours[i] = 1}else {hours[i] = -1}}
}
func max(x,y int) int {if x > y {return x}return y
}

总结

1)对于子数组/子串问题,紧密连续前缀和/滑动窗口/单调栈。
2)挖掘内在规律,可以简化代码,降低时空复杂度或消耗量。比如这里单调栈,将前缀和简化;比如这里不用TreeMap排序,数值只有1/0/-1三种可能,前缀和必定连续。

参考文献

[1] LeetCode 表现良好的最长时段
[2] LeetCode 官方题解

http://www.lryc.cn/news/8301.html

相关文章:

  • Python 获取当前系统时间
  • pytorch基础入门教程
  • RTSP协议交互时TCP/UDP的区别 以及视频和音频的区别 以及H264/H265的区别
  • 调用大智慧L2接口是什么原理?作用是什么?
  • 数据结构 - 栈 与 队列 - (java)
  • CellularAutomata元胞向量机-8-渗流集群MATLAB代码分享
  • iOS UI自动化测试详解
  • Mybatis源码分析(九)Mybatis的PreparedStatement
  • winfrom ui
  • 中国国家级地面气象站基本气象要素日值数据集(V3.0)
  • 【Python语言基础】——Python NumPy 数组副本 vs 视图
  • Spring Cloud_OpenFeign服务接口调用
  • 十三、GIO GTask
  • ch4_1存储器
  • Doris通过Flink CDC接入MySQL实战
  • 搭建zookeeper高可用集群详细步骤
  • Scala 变量和数据类型(第二章)
  • 【JVM基础内容速查表】JVM基础知识 默认参数 GC命令 工具使用 JVM参数设置、说明、使用方法、注意事项等(持续更新)
  • C语言经典编程题100例(61~80)
  • toxssin:一款功能强大的XSS漏洞扫描利用和Payload生成工具
  • Keepalived与HaProxy的协调合作原理分析
  • 抖音如何找到博主视频推广?筛选博主要看那些数据
  • Win11的两个实用技巧系列之如何关闭登录密码?
  • 润普挂卷失败之老卷宗对接NP无法获取案件信息问题排查
  • 产品经理面试题思考及回答思路(一)
  • Routability-Driven Macro Placement with Embedded CNN-Based Prediction Model
  • 论一个上班族如何一次性通过PMP考试
  • Web前端:使用Angular CLI时的最佳实践和专业技巧
  • 从0到1一步一步玩转openEuler--15 openEuler使用DNF管理软件包
  • 【java】Spring Boot --spring boot项目整合xxl-job