{x}
blog image

Shortest Subarray with Sum at Least K

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

Solution Explanation:

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:

  • Time Complexity: O(n). Each element of the prefix sums array is added to the deque at most once, and removed from the deque at most once.
  • Space Complexity: O(n) in the worst case, to store the deque and the prefix sum array.

Code Explanation (Python):

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.