We need to find the shortest contiguous subarray whose sum is at least k. If this problem only had positive numbers, a standard sliding window would do the job because expanding the window always increases the sum and shrinking always decreases it. But the presence of negative numbers breaks that monotonic property. Shrinking the window can increase the sum (by dropping a negative element), and expanding it can decrease the sum.
This rules out a plain two-pointer approach. We need a way to track which starting points are still worth considering as we move through the array.
Prefix sums combined with a monotone deque solve this in linear time. For any subarray nums[i..j], its sum equals prefix[j+1] - prefix[i]. So finding a subarray with sum at least k is equivalent to finding indices i < j where prefix[j] - prefix[i] >= k and j - i is minimized.
1 <= nums.length <= 10^5 -- With up to 100,000 elements, we need O(n) or O(n log n). Anything quadratic will time out.-10^5 <= nums[i] <= 10^5 -- Negative numbers are present. This rules out the standard sliding window approach since the window sum isn't monotonically related to window size.1 <= k <= 10^9 -- k can be large, so it's possible no valid subarray exists.10^5 * 10^5 = 10^10, which overflows a 32-bit integer. The accumulator and prefix array must use a 64-bit type (long / long long / int64).Check every possible subarray. For each starting index i, extend the subarray to the right, accumulating the sum. The first ending index j where the running sum reaches at least k gives the shortest valid subarray that starts at i, because j only grows as we extend, so the first crossing has the smallest length. Once that happens, we can stop extending from this start and move on to the next one.
Negative numbers do not break this inner-loop logic. They only mean we cannot stop scanning starting indices early: a later start can still produce a shorter valid subarray, so we must try all of them.
minLength = infinity.i from 0 to n-1:currentSum = 0.j from i to n-1:nums[j] to currentSum.currentSum >= k, update minLength = min(minLength, j - i + 1) and break.minLength is still infinity, return -1. Otherwise, return minLength.Input:
With k = 3, we scan every starting index and extend until the running sum reaches 3.
i = 0: sum at j=0 is 2 (below 3), at j=1 is 1 (below 3), at j=2 is 3 (reaches 3). Length 2 - 0 + 1 = 3. Record minLength = 3, break.i = 1: sum at j=1 is -1, at j=2 is 1. Never reaches 3. No update.i = 2: sum at j=2 is 2. Never reaches 3. No update.Only the subarray from index 0 to 2 qualifies, so the answer is 3.
The brute force recomputes overlapping sums and discards what it learns between starting indices. The next approach precomputes prefix sums once and uses a deque to find the best starting point for each ending position in amortized constant time.
Reformulate the problem in terms of prefix sums. Define prefix[0] = 0 and prefix[j] = nums[0] + nums[1] + ... + nums[j-1]. The sum of subarray nums[i..j-1] is prefix[j] - prefix[i], so we need the smallest j - i such that prefix[j] - prefix[i] >= k with i < j.
For a fixed j, the best starting point is the largest i (closest to j) such that prefix[i] <= prefix[j] - k. Not all indices are worth keeping as candidates.
Consider two indices i1 < i2 where prefix[i1] >= prefix[i2]. Index i1 is dominated by i2 for every future j: i2 gives a subarray sum that is at least as large (its prefix is smaller or equal) and a shorter subarray (it sits closer to any endpoint). So i1 can be discarded. The surviving candidates form a strictly increasing sequence of prefix sums, which we maintain in a deque ordered by index.
Once prefix[j] - prefix[i] >= k for the index i at the front of the deque, we record the length and remove i permanently. Any later j' > j paired with the same i would only produce a longer subarray, so i has already given its shortest answer.
The two while loops are nested inside the for loop, but the total work is still linear. Each index j is pushed onto the deque exactly once, and it can be removed at most once, either from the front (when it produces a valid subarray) or from the back (when a smaller prefix sum dominates it). Across all n+1 iterations, the number of pop operations is bounded by the number of pushes, so the while loops do O(n) work in total.
prefix[j] = nums[0] + nums[1] + ... + nums[j-1].minLength = infinity.j from 0 to n:prefix[j] - prefix[deque.front()] >= k:minLength = min(minLength, j - deque.front()).prefix[j] <= prefix[deque.back()]:j onto the back of the deque.minLength if it was updated, otherwise -1.