一个人内耗,说明他活在过去;一个人焦虑,说明他活在未来。只有当一个人平静时,他才活在现在。
日常
1、起床6:00√
2、健身2h
3、LeetCode刷了4题
- 无重叠区间
- 对于贪心算法,可以先对数组进行排序,然后再根据排序后的性质对其进行贪心处理
- 当有多个维度或者贪心时,可以考虑先进行排序,确定一个维度后再进行判断,此题对左端点进行排序,然后从前向后遍历区间,如果当前区间左端点小于上一个区间的右端点,则说明这两个区间是重叠的,则要去除一个,为了使得去除区间的次数最少,则应该去除右端点更大的区间,因为右端点更大说明可能会再次重叠,故直接对当前区间右端点取最小值,相当于去除右端点最大的区间
- 和射爆气球类似,还是从前向后遍历每个数组,然后判断相邻两个区间是否有重叠,即当前区间的左端是否小于上一个区间右端,如果有重叠,则局部最优是移除右端范围更大的区间(使得去除次数最少),因为左部分一定是无重叠,故为了使得移除次数最小,则要移除右端范围更大的区间,故此时可以直接对当前区间的右端进行修改,取当前区间右端和上一个区间右端的最小值,代表移除了相邻两个区间右端范围更大的区间
- 当前区间左边一定是无重叠的,当没有与上一个区间重叠时,直接继续遍历
- 当重叠时,为了减少移除操作的次数,故局部最优是移除右端范围更大的区间
- 合并重叠区间
- 仍然是先对区间进行排序,然后从前向后遍历所有区间,判断是否重叠,如果重叠(当前区间左端点小于上一个区间右端点),则更新当前遍历到的区间,使其等于合并后的总区间,左端点等于上一个元素的左端点(保证区间最大),**右端点等于当前区间和上一个区间右端点的最大值(保证区间最大)****,然后继续遍历,因为要保存合并后的区间,故当重叠时,直接在当前区间的基础上修改为合并后的区间,左端点取最大值,右端点也取最大值,当不重叠时,上一个区间就是要保存的区间
- 如果不重叠,则将上一个区间加入到目标数组ArrayList或者Linklist中,然后最后再使用
StoArray(new int[][])
转换为二维数组
- 贪心周总结
- 贪心问题如果存在数组等多维情况,可以先进行排序使得某一维固定,然后再进行贪心,可以先排序使得某一个维度固定,然后再继续
- 用最少数量的箭射爆气球:按照左边界进行排序后,如果气球重叠了,重叠气球中右边边界的最小值(要保证包含重叠的区间) 之前的区间一定需要一个弓箭,不重叠时将前面的重叠射爆,重叠时将右端点更新为最小值,保证不重叠时可以一次射爆前面的所有气球
- 无重叠区间:当重叠时,要移除右端范围更大的区间,从而使得移除次数最少
- 划分字母区间:找到一个片段内的最大右边界,并在遍历时对其不断更新,使得同一个字母最多出现在一个片段中;通过字符出现最远距离取并集的方法,把出现过的字符都圈到一个区间里。
- 合并重叠区间:仍然是排序后从前向后遍历,此时当相邻两个区间重叠时,则合并,并使得新区间保存到当前区间内,然后继续遍历;每次合并都取最大的右边界,这样就可以合并更多的区间了,整体最优:合并所有重叠的区间。
- 缺失的第一个正数
- 因为要求空间复杂度为常数,且要求时间复杂度为O(N),故必须在原数组的基础上对其操作从而求出结果
- 数组长度为 n ,则此时最大的缺失最小正数是 n+1,故可以考虑遍历整个数组,使得负数全为 n + 1,此时数组中全为正数,且只有在 1 ~ n 范围内的数才是存在的正数,然后再遍历数组,如果元素小于 n+1 ,则对其下标对应元素改为负数,表示下标对应正数存在,此时遍历时某个元素可能被改变为负数,故要判断其绝对值是否小于 n+1,遍历结束后此时所有下标位置为负数的都说明对应下标的正数存在,故第一个正数所在的下标就是缺失的最小正数
- 划分字母区间
- 要尽可能把字符串划分为更多的片段,故局部最优是保证某个片段是最短的,而某一个字母最多出现在一个片段中,故遍历字符串,每遇到一个字母,找到出现的最后一个位置(字符串从后向前查找第一个位置就是最后一个位置),然后更新该片段的右端点取最大值,保证最多出现在一个片段中,然后继续遍历该片段重复操作,直到到达片段末尾,此时将该片段划分,然后继续寻找下一个片段
- 把字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。
- 从前向后遍历,每遍历一个元素求出其在字符串中最后出现的位置(此时从后向前遍历字符串第一个遇到的下标就是该元素最后出现的位置),然后从当前到最后最小的位置必须在同一个片段中,继续遍历片段中的字母,同时更新片段最右端的长度,使得每个字母最多出现在一个片段中
- 如果当前元素下标与当前片段右端相同时,说明当前片段是满足条件的最小片段,此时就可以划分出去,记录当前片段的长度,然后继续寻找下一个片段
4、复盘22:00√
不复盘等于白学!!!
学习和感想
1. RabbitMQ实现延迟消息
1. 介绍
- 延迟消息:生产者发送消息时指定一个时间,消费者不会立刻收到消息,而是在指定时间之后才收到消息,即定时发送消息
- 下单后会立刻扣减库存,且会等待用户在指定时间内支付,如果未支付则恢复库存,此时可以通过定时任务定时扫描数据库,如果未支付则取消订单,但会使得数据库的压力太大,故不可以使用定时任务定时扫描
- 此时就可以通过延时消息来实现指定时间后判断是否支付,即下单后设置一个延迟消息,该消息在设置的延时后会执行一次查询是否支付的操作,如果没有支付则删除订单恢复库存
2. 死信交换机实现延迟消息
- 死信消息:消息处理失败且设置不再回传时、消息达到过期时间无人消费、队列堆积
- 如果队列通过dead-letter-exchange属性指定了一个交换机,则该队列中的死信消息会投递到该交换机,则该交换机就是死信交换机,此时可以通过死信交换机实现延迟消息,为某个消息设置过期时间,然后投递的队列不设置消费者,则过期后会投递到指定的死信交换机,此时再对该死信交换机的队列进行消费,就可以实现消息先在某个队列中等待指定时间过期后再被消费,从而实现延迟消费
3. 延迟消息插件
- 通过设置死信交换机的方式实现延迟消息,此时会很复杂,因为要额外设置一个交换机和队列,且要进行绑定,故RabbitMQ引入了实现延迟消息的插件,先进行下载并加载到RabbitMQ服务容器中,然后直接创建支持消息延迟的交换机即可(设置交换机的 delayed 属性为 true),其会根据投递到当前交换机的消息设置的delay时间对其延迟,然后再投递到绑定的队列中,从而实现延迟消息
- 延迟消息插件设计了一种支持延迟消息功能的交换机,当消息投递到交换机后可以暂存一段时间,到期后再投递到队列
- 要下载延迟消息插件并放到rabbitMQ服务容器的插件目录下,然后执行docker exec —实现在容器内执行指定的指令还开启插件![[attachments/Pasted image 20241112125914.png]]
- 此时就可以在创建交换机时,通过配置交换机的 delayed 参数 = true 来创建实现延迟消息的交换机
- 然后发送消息时通过消息头x-delay设置过期时间发送到实现延迟消息的交换机,必须设置消息的过期时间再发送到指定的交换机中
4. 取消超时订单
- 定时任务是设置一个时钟,当时间到了后会自动执行,此时会占用CPU,如果定时任务很多时,对CPU的压力很大,CPU会一直监控定时任务判断是否到达时间,故CPU压力很大,故此时可以使用将一个定时任务拆分为多个任务
- 设置延迟消息是使用定时器,如果并发很高,会导致消息堆积过多,此时定时过多会对MQ压力很大,而且大部分订单都会在定时时间内执行,但在MQ中却要等待很久,浪费资源
- 可以将一个长时间的延迟消息拆分为多个短时间的延迟消息,使得多次检查,如果满足则执行业务取消定时