找到最短的連續子數組的和至少爲k
維護前綴和b,那麼要我們要找的就是滿足b[i] - b[j] >=k 的最大的j是多少,樸素的實現的話複雜度是O(N^2)的
注意到如果前綴和b[x] >= b[y]的話,那麼x永遠不可能成爲解,因爲這個時候如果x滿足 b[i] - b[x] >= k的話,
那麼j也一定滿足b[i] - b[y] >= k,並且y和i組成的數組要比x和i組成的數組更短
因此候選的解一定是一定(嚴格)單調上升的序列,我們可以用一個雙端隊列來實現
具體的話
每次入隊的時候,如果當前和比隊尾的和大,就一直出隊
尋找解的時候,從隊首一直向後找,找到最大的下標即可,之前的就可以出隊了,因爲他們後面也不可能成爲更優的解了。
每個下標最多都只會進隊和出隊一次,複雜度是O(N)
public int shortestSubarray(int[] A, int K) {
//單調隊列,維護前綴和B[], 如果 B[i] >= B[j], 那麼i永遠不可能成爲最有解
int len = A.length;
int[] b = new int[len + 1];
for (int i = 1; i <= len; i++) b[i] = b[i - 1] + A[i - 1];
int res = Integer.MAX_VALUE;
//d是一個雙端隊列,維護的是b數組的下標
Deque<Integer> d = new ArrayDeque<>();
d.add(0);
for (int i = 1; i <= len; i++) {
while (!d.isEmpty() && b[i] - b[d.getFirst()] >= K) {
res = Math.min(res, i - d.getFirst());
d.pollFirst();
}
//根據上述的性質,隊列維護的前綴和一定是一個(嚴格)單調上升的
while (!d.isEmpty() && b[i] <= b[d.getLast()]) {
d.pollLast();
}
d.add(i);
}
return res == Integer.MAX_VALUE ? -1 : res;
}