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

161 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

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

返回 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 <= A.length <= 50000
  • -10 ^ 5 <= A[i] <= 10 ^ 5
  • 1 <= K <= 10 ^ 9

解题思路

  1. 对于新加入的y,前面的P[x]都要比新加入的P[y]要小,比P[y]大的P[?]都要pop掉,甚至如果都比P[y]大,整个队列都要清空。为什么?

因为对于当前y来说,必须满足P[y]-P[x]>=K,k又必然是正数,所以p[y]必须大于p[x]。对于y后面的y2来说,即使满足P[y2]-P[x]>=K,[x,y2]之间也不是最短的,因为p[y]<p[x],所以必然满足P[y2]-P[y]>=K,y比x更加接近y2,生成的长度更短,所以x可以直接pop掉,对答案不会产生影响

  1. 为什么当队列里第一个x满足P[y]-P[x]>=K的时候,第一个x可以被pop掉?

因为此时我们构成了一个P[y]-P[x]>=K,这个y已经是最接近x的了,即长度最短,后面即使还能满足P[y]-P[x]>=K,长度也不够当前长度短

代码


class Solution {

    public int shortestSubarray(int[] nums, int k) {

        int n=nums.length,res=n+1;

        LinkedList<Integer> list=new LinkedList<>();

        long[] pre=new long[n+1];

        for(int i=1;i<=n;i++)

            pre[i]=pre[i-1]+(long)nums[i-1];

        for(int i=0;i<n+1;i++)

        {

            while(!list.isEmpty()&&pre[i]<pre[list.getLast()])

                list.removeLast();

            while(!list.isEmpty()&&pre[i]-pre[list.getFirst()]>=k)

            {

                res=Math.min(res,i-list.removeFirst());

            }

            list.add(i);

        }

        return res==n+1?-1:res;

    }

}