862. 和至少为 K 的最短子数组

题目描述

数组含有负数,求一个最短子数组,子数组的和>=k

f1-单调队列

基本分析

  1. 子数组和的问题怎么优化?前缀和
  2. 相比于暴力去枚举,可以有哪两个思路优化?用一个数据结构来存可能的前缀,(1)过河拆桥,如果一个前缀值满足了条件,那么他不用再考虑了,从前面弹出;(2)后浪更迭,当前遍历到的值<= 尾部的值,尾部的值需要弹出。最终保证q中的索引对应的s值是单调上升的。

代码

显式计算前缀和
class Solution:
def shortestSubarray(self, nums: List[int], k: int) -> int:
ans = inf
s = list(accumulate(nums, initial = 0))
q = deque()
for i, cur_s in enumerate(s):
# 过河拆桥
while q and cur_s - s[q[0]] >= k:
ans = min(ans, i - q[0])
q.popleft()
# 后浪推前浪
while q and s[q[-1]] >= cur_s:
q.pop()
q.append(i)
return ans if ans < inf else -1
一边遍历一边计算
class Solution:
def shortestSubarray(self, nums: List[int], k: int) -> int:
ans = inf
q = deque([(0, 0)])
cur_s = 0
for i, num in enumerate(nums, 1):
cur_s += num
while q and cur_s - q[0][0] >= k:
ans = min(ans, i - q[0][1])
q.popleft()
while q and cur_s <= q[-1][0]:
q.pop()
q.append((cur_s, i))
return ans if ans < inf else -1

总结

  1. 去掉前缀和的写法需要注意什么?(1)nums遍历如果从0开始,队列中需要放下标-1;(2)因为没有显式写出前缀和数组,求之前的时候就需要从队列中去拿,所以队列存的时候除了索引,还要存对应的前缀和的值。
  2. 计算长度的时候为啥不+1?cur_s对应的区间是0-i-1的和,q[0]对应的区间是0-q[0]-1的和,子区间的索引是q[0]到i-1,所以不再额外+1。
posted @   zhangk1988  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示