Return the length of the shortest, non-empty, contiguous subarray of A with sum at least K.
If there is no non-empty subarray with sum at least K, return -1.
Example 1:
Input: A = [1], K = 1
Output: 1
Example 2:
Input: A = [1,2], K = 4
Output: -1
Example 3:
Input: A = [2,-1,2], K = 3
Output: 3
Note:
1 <= A.length <= 50000-10 ^ 5 <= A[i] <= 10 ^ 51 <= K <= 10 ^ 9
思路:这题跟Minimum Size Subarray Sum 很相似,不同的是,加入了负数,使得问题变复杂了。思路就是:求区间和,很容易想到prefixsum,这个很好求出,但是怎么扫描去求sum>=k的最小区间长度,sum[i] .... sum[j].... sum[k]
如果sum[i] > sum[j], sum[k] - sum[i] >=k, 那么sum[k] - sum[j] 更加>=k,同时j > i,那么j到k区间会更小,那么sum[i]就没必要存,发现这个性质那么就是单调栈,前面的数sum[i], 比当前的数sum[j]要大,就没必要存,那么栈里面就是单调递增的,我们要保持里面是递增的,那么后面进来的数,如果比last要小,则踢掉前面的数,为什么?是因为如果存了,last > i, future - last >= k, 那么future - i 更加>= k, 所以 last比i大,没必要存;
More detailed on this, we always add at the LAST position
B[d.back] <- B[i] <- ... <- B[future id]
B[future id] - B[d.back()] >= k && B[d.back()] >= B[i]
B[future id] - B[i] >= k too
前后都要进出,那么用deque可以满足要求。这里要注意一点,长度是 i - deque.peekFirst()。为什么,是因为sum[j] - sum[i] ,subarray的长度其实是i + 1,...j,那么就是j - i + 1 - 1 = j - i;
记住prefixsum,都要用long来防止溢出;
class Solution {
public int shortestSubarray(int[] A, int K) {
if(A == null || A.length == 0) {
return -1;
}
int n = A.length;
long[] prefixsum = new long[n + 1];
prefixsum[0] = 0;
for(int i = 1; i <= n; i++) {
prefixsum[i] = prefixsum[i - 1] + A[i - 1];
}
Deque<Integer> arrayDeque = new ArrayDeque<Integer>();
int res = Integer.MAX_VALUE;
for(int i = 0; i <= n; i++) {
while(!arrayDeque.isEmpty() && prefixsum[i] - prefixsum[arrayDeque.peekFirst()] >= K) {
res = Math.min(res, i - arrayDeque.peekFirst());
arrayDeque.pollFirst();
}
while(!arrayDeque.isEmpty() && prefixsum[i] <= prefixsum[arrayDeque.peekLast()]) {
arrayDeque.pollLast();
}
arrayDeque.offer(i);
}
return res == Integer.MAX_VALUE ? -1 : res;
}
}

本文探讨了一种算法,用于寻找数组中满足特定条件的最短连续子数组,即子数组的和至少为预设值K。通过使用前缀和与双端队列的数据结构,该算法能有效地解决这一问题,特别适用于包含正数和负数的数组。
645

被折叠的 条评论
为什么被折叠?



