As David indicates, you can't use the sliding/stretching window technique when there are negative numbers in the array, because the sum doesn't grow monotonically with the window size.
You can still solve this in O(n log n) time, though, using a technique that is usually used for the "sliding window minimum/maximum" problem.
First, transform your array into a prefix sum array, by replacing each element with the sum of that element and all the previous ones. Now your problem changes to "find the closest pair of elements with difference >= X" (assuming array[-1]==0).
As you iterate though the array, you need to find, for each i, the latest index j such that j < i and array[j] <= array[i]-x.
In order to do that quickly, first note that array[j] will always be less than all the following elements up to i, because otherwise there would be a closer element to choose.
So, as you iterate through the array, maintain a stack of the indexes of all elements that are smaller than all the later elements you've seen. This is easy and takes O(n) time overall -- after processing each i, you just pop all the indexes with >= values, and then push i.
Then for each i, you can do a binary search in this stack to find the latest index with a small enough value. The binary search works, because the values for index in the stack increase monotonically -- each element must be less than all the following ones.
With the binary search, to total time increases to O(n log n).
In JavaScript, it looks like this:
var shortestSubarray = function(A, K) {
//transform to prefix sum array
let sum=0;
const sums = A.map(val => {
sum+=val;
return sum;
});
const stack=[];
let bestlen = -1;
for(let i=0; i<A.length; ++i) {
const targetVal = sums[i]-K;
//binary search to find the shortest acceptable span
//we will find the position in the stack *after* the
//target value
let minpos=0;
let maxpos=stack.length;
while(minpos < maxpos) {
const testpos = Math.floor(minpos + (maxpos-minpos)/2);
if (sums[stack[testpos]]<=targetVal) {
//value is acceptable.
minpos=testpos+1;
} else {
//need a smaller value - go left
maxpos=testpos;
}
}
if (minpos > 0) {
//found a span
const spanlen = i - stack[minpos-1];
if (bestlen < 0 || spanlen < bestlen) {
bestlen = spanlen;
}
} else if (bestlen < 0 && targetVal>=0) {
// the whole prefix is a valid span
bestlen = i+1;
}
// Add i to the stack
while(stack.length && sums[stack[stack.length-1]] >= sums[i]) {
stack.pop();
}
stack.push(i);
}
return bestlen;
};
Leetcode says:
SUCCESS:
Runtime: 216 ms, faster than 100.00% of JavaScript online submissions
for Shortest Subarray with Sum at Least K.
Memory Usage: 50.1 MB, less than 37.37% of JavaScript online
submissions for Shortest Subarray with Sum at Least K.
I guess most people used a slower algorithm.