此题解采用前缀和和单调队列的组合方法来解决问题。首先,使用前缀和数组来记录从数组开始到当前位置的所有元素的累加和,这样可以快速计算任意子数组的和。然后,使用一个单调递增的队列来存储前缀和数组的索引,队列中的每个元素代表一个潜在的最小起点位置。对于每个新的前缀和,我们首先从队尾开始移除那些不再可能成为最短子数组起点的元素(因为一个更小的前缀和已出现)。然后,从队首开始检查是否存在有效的子数组,即当前前缀和与队首索引对应的前缀和之差至少为k。如果存在,更新结果并弹出队首元素,因为更短的有效子数组不可能再以此队首元素为起点。最后,将当前前缀和的索引加入队列。这一过程持续到遍历完所有的前缀和,最后根据结果变量判断是否找到了满足条件的子数组。
时间复杂度: O(n)
空间复杂度: O(n)
class Solution:
def shortestSubarray(self, nums: List[int], k: int) -> int:
from itertools import accumulate
from collections import deque
# 前缀和数组,初始值为0以方便计算从头开始的子数组和
preSum_lst = list(accumulate(nums, initial=0))
res = float('inf') # 结果初始化为无穷大
stack = deque() # 单调队列,存放前缀和的索引
for i, v in enumerate(preSum_lst):
# 维持队列的单调递增性
while stack and v < preSum_lst[stack[-1]]:
stack.pop()
# 检查当前前缀和与队首前缀和之差是否满足条件
while stack and v - preSum_lst[stack[0]] >= k:
res = min(res, i - stack.popleft())
stack.append(i) # 将当前索引加入队列
# 如果res仍为无穷大,说明没有找到满足条件的子数组
return -1 if res == float('inf') else res