LEETCODE.862 和至少为 K 的最短子数组

894 阅读1分钟

返回 A 的最短的非空连续子数组的长度,该子数组的和至少为 K 。

如果没有和至少为 K 的非空子数组,返回 -1 。

示例 1:

输入:A = [1], K = 1
输出:1

示例 2:

输入:A = [1,2], K = 4
输出:-1

示例 3:

输入:A = [2,-1,2], K = 3
输出:3

提示:

1.1 <= A.length <= 50000
2.-10 ^ 5 <= A[i] <= 10 ^ 5
3.1 <= K <= 10 ^ 9

代码:

public class Solution {
    public int shortestSubarray(int[] A, int K) {
        int len = A.length, min = len + 1;
        int sum[] = new int[len + 1];
        for (int i = 0; i < len; i++) {
            sum[i + 1] = A[i] + sum[i];
        }

        LinkedList<Integer> queue = new LinkedList<>();
        for (int i = 0; i <= A.length; i++) {
            // 步骤1,保证留在队列中的都是前缀和比sum[i]小的.
            // 举个例子,有 m < n < i, 如果sum[m] >= sum[n],因此有A[m...n) <= 0.
            // 当判断i时,可得,A[m...i) = A[m...n) + A[n...i),因为 A[m...n) <= 0,简单推理即可得A[n...i) >= A[m...i).
            // 有上面的推断可以得出,如果A[m...i) >= K,那么A[n...i)也必然大于等于K,而[n...i)的长度明显比[m...i)短.
            // 因此只需要比较i与n即可,而不必比较i与m,因此可以将m直接抛弃.
            while (queue.size() > 0 && sum[i] <= sum[queue.getLast()]) {
                queue.pollLast();
            }

            //步骤2. 如果满足,则去掉头部f,因为后面的下标p(p > i)即使满足 sum[p] - sum[f] >= k,那p - f的长度也比i - f的长度长.
            while (queue.size() > 0 && sum[i] - sum[queue.getFirst()] >= K) {
                min = Math.min(min, i - queue.getFirst());
                queue.pollFirst();
            }

            queue.addLast(i);
        }

        return min <= len ? min : -1;
    }
}