题目描述
数组含有负数,求一个最短子数组,子数组的和>=k
基本分析
- 子数组和的问题怎么优化?前缀和
- 相比于暴力去枚举,可以有哪两个思路优化?用一个数据结构来存可能的前缀,(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)nums遍历如果从0开始,队列中需要放下标-1;(2)因为没有显式写出前缀和数组,求之前的时候就需要从队列中去拿,所以队列存的时候除了索引,还要存对应的前缀和的值。
- 计算长度的时候为啥不+1?cur_s对应的区间是0-i-1的和,q[0]对应的区间是0-q[0]-1的和,子区间的索引是q[0]到i-1,所以不再额外+1。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下