from collections import deque
class Solution:
def shortestSubarray(self, nums, k):
n = len(nums)
prefix = [0] * (n + 1)
for i in range(n):
prefix[i + 1] = prefix[i] + nums[i]
dq = deque()
res = n + 1
for i in range(n + 1):
while dq and prefix[i] - prefix[dq[0]] >= k:
res = min(res, i - dq.popleft())
while dq and prefix[i] <= prefix[dq[-1]]:
dq.pop()
dq.append(i)
return res if res <= n else -1
#include <vector>
#include <deque>
#include <climits>
using namespace std;
class Solution {
public:
int shortestSubarray(vector<int>& nums, int k) {
int n = nums.size();
vector<long long> prefix(n + 1, 0);
for (int i = 0; i < n; ++i)
prefix[i + 1] = prefix[i] + nums[i];
deque<int> dq;
int res = n + 1;
for (int i = 0; i <= n; ++i) {
while (!dq.empty() && prefix[i] - prefix[dq.front()] >= k) {
res = min(res, i - dq.front());
dq.pop_front();
}
while (!dq.empty() && prefix[i] <= prefix[dq.back()])
dq.pop_back();
dq.push_back(i);
}
return res <= n ? res : -1;
}
};
import java.util.*;
class Solution {
public int shortestSubarray(int[] nums, int k) {
int n = nums.length;
long[] prefix = new long[n + 1];
for (int i = 0; i < n; ++i)
prefix[i + 1] = prefix[i] + nums[i];
Deque<Integer> dq = new ArrayDeque<>();
int res = n + 1;
for (int i = 0; i <= n; ++i) {
while (!dq.isEmpty() && prefix[i] - prefix[dq.peekFirst()] >= k) {
res = Math.min(res, i - dq.pollFirst());
}
while (!dq.isEmpty() && prefix[i] <= prefix[dq.peekLast()])
dq.pollLast();
dq.addLast(i);
}
return res <= n ? res : -1;
}
}
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var shortestSubarray = function(nums, k) {
const n = nums.length;
const prefix = new Array(n + 1).fill(0);
for (let i = 0; i < n; ++i)
prefix[i + 1] = prefix[i] + nums[i];
const dq = [];
let res = n + 1;
for (let i = 0; i <= n; ++i) {
while (dq.length && prefix[i] - prefix[dq[0]] >= k) {
res = Math.min(res, i - dq.shift());
}
while (dq.length && prefix[i] <= prefix[dq[dq.length - 1]])
dq.pop();
dq.push(i);
}
return res <= n ? res : -1;
};
Given an integer array nums
and an integer k
, find the length of the shortest, non-empty, contiguous subarray of nums
whose sum is at least k
. If there is no such subarray, return -1
.
nums
.
The first instinct might be to check all possible subarrays and find the shortest one whose sum is at least k
. However, this brute-force approach is inefficient, especially for long arrays, because it requires checking every possible subarray.
For positive numbers, a sliding window works well, but negative numbers break the simple sliding window logic, because removing a negative number could increase the sum. So, we need a strategy that works even with negative numbers.
To optimize, we can use prefix sums to quickly calculate subarray sums, and a data structure (like a deque) to efficiently track candidates for the start of our subarray as we scan through the array.
Our optimized solution uses prefix sums and a monotonic queue (deque) to efficiently find the shortest qualifying subarray.
prefix
where prefix[i]
is the sum of nums[0]
to nums[i-1]
.i
to j-1
is prefix[j] - prefix[i]
.prefix
in increasing order.i
, we check if prefix[i] - prefix[dq[0]] >= k
. If so, we found a subarray from dq[0]
to i-1
with sum at least k
.prefix[i]
is less than or equal to prefix[dq[-1]]
, since they can't help us find a shorter subarray in the future.-1
.The deque ensures we efficiently keep track of the best candidates for the start of a valid subarray, and prefix sums let us compute subarray sums in constant time.
Suppose nums = [2, -1, 2]
and k = 3
.
[0, 2, 1, 3]
i = 0
:
i = 1
:
prefix[1] - prefix[0] = 2 - 0 = 2 < 3
i = 2
:
prefix[2] - prefix[0] = 1 - 0 = 1 < 3
prefix[2] <= prefix[1]
, so remove 1 from back.i = 3
:
prefix[3] - prefix[0] = 3 - 0 = 3 >= 3
, so subarray [0,2] is valid, length 3.prefix[3] - prefix[2] = 3 - 1 = 2 < 3
, so stop.The optimized approach is much faster for large arrays, especially when negative numbers are present.
To solve the "Shortest Subarray with Sum at Least K" problem efficiently, we use prefix sums to quickly calculate subarray sums and a monotonic deque to track the best starting points for subarrays. This approach handles negative numbers and finds the shortest qualifying subarray in linear time. The key insight is using the deque to maintain a list of candidates in increasing order, discarding those that can never lead to a shorter or better subarray. This results in a clean, elegant, and highly efficient solution.