Given an integer array nums
and an integer k
, return the length of the shortest non-empty subarray of nums
with a sum of at least k
. If there is no such subarray, return -1
.
A subarray is a contiguous part of an array.
Example 1:
Input: nums = [1], k = 1 Output: 1
Example 2:
Input: nums = [1,2], k = 4 Output: -1
Example 3:
Input: nums = [2,-1,2], k = 3 Output: 3
Constraints:
1 <= nums.length <= 105
-105 <= nums[i] <= 105
1 <= k <= 109
This problem asks to find the shortest subarray whose sum is at least k. A naive approach of checking all subarrays would have O(n^2) time complexity. We can optimize this using a monotonic deque and prefix sums.
1. Prefix Sums:
First, we calculate the prefix sums of the input array nums
. The prefix sum s[i]
represents the sum of elements from nums[0]
to nums[i-1]
. This allows us to efficiently calculate the sum of any subarray: the sum of the subarray from index i
to j
(inclusive) is simply s[j+1] - s[i]
.
2. Monotonic Deque:
We use a deque (double-ended queue) to store indices of the prefix sums. This deque maintains a monotonically increasing order of prefix sums. This is crucial for efficiently finding the shortest subarray. The deque stores indices, not the prefix sum values themselves.
3. Algorithm:
The algorithm iterates through the prefix sums:
Dequeue Operation: For each prefix sum s[i]
, we check the front of the deque. If the difference between s[i]
and the prefix sum at the front of the deque (s[q[0]]
) is greater than or equal to k
, it means we've found a subarray with a sum at least k
. We remove the front element from the deque, updating the minimum length ans
. We keep removing elements from the front as long as this condition is met.
Enqueue Operation: After the dequeue operation, we check the back of the deque. If the prefix sum at the back of the deque is greater than or equal to the current prefix sum s[i]
, we remove elements from the back. This ensures the deque maintains a monotonically increasing order. Finally, we add the current index i
to the back of the deque.
4. Time and Space Complexity:
from itertools import accumulate
from collections import deque
import math
class Solution:
def shortestSubarray(self, nums: List[int], k: int) -> int:
s = list(accumulate(nums, initial=0)) # Calculate prefix sums
q = deque() # Initialize deque
ans = math.inf # Initialize minimum length to infinity
for i, v in enumerate(s): # Iterate through prefix sums
while q and v - s[q[0]] >= k: # Dequeue operation
ans = min(ans, i - q.popleft()) # Update minimum length
while q and s[q[-1]] >= v: # Enqueue operation - maintain monotonic order
q.pop()
q.append(i) # Add current index to deque
return -1 if ans == math.inf else ans # Return result
The code in other languages follows the same logic, with minor syntactic differences. The core idea of using a monotonic deque and prefix sums to solve this problem efficiently remains consistent across all implementations.