import java.util.*;

/**
 * NC343 和大于等于K的最短子数组
 * @author d3y1
 */
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型ArrayList
     * @param k int整型
     * @return int整型
     */
    public int shortestSubarray (ArrayList<Integer> nums, int k) {
        // return solution1(nums, k);
        // return solution2(nums, k);
        return solution3(nums, k);
    }

    /**
     * 二分
     * @param nums 正整数数组!
     * @param k
     * @return
     */
    private int solution1(ArrayList<Integer> nums, int k){
        int n = nums.size();

        // 前缀和
        long[] preSum = new long[n+1];
        for(int i=1; i<=n; i++){
            preSum[i] = preSum[i-1]+nums.get(i-1);
        }

        int result = Integer.MAX_VALUE;
        int left = 1;
        int right = n;
        int mid;
        // 二分
        while(left <= right){
            mid = left+(right-left)/2;
            if(check(preSum, k, mid)){
                result = Math.min(result, mid);
                right = mid-1;
            }else{
                left = mid+1;
            }
        }

        return result==Integer.MAX_VALUE?-1:result;
    }

    /**
     * 校验gap大小窗口是否满足条件(preSum[j]-preSum[i] >= k)
     * @param preSum
     * @param target
     * @param gap
     * @return
     */
    private boolean check(long[] preSum, int target, int gap){
        for(int i=0,j=i+gap; j<preSum.length; i++,j++){
            if(preSum[j]-preSum[i] >= target){
                return true;
            }
        }

        return false;
    }

    /**
     * 双指针: 滑动窗口
     * @param nums 正整数数组!
     * @param k
     * @return
     */
    private int solution2(ArrayList<Integer> nums, int k){
        int n = nums.size();
        int result = Integer.MAX_VALUE;

        int left=0;
        int right=0;
        int sum = 0;
        int numL,numR;
        while(right < n){
            numR = nums.get(right++);
            if(numR >= k){
                return 1;
            }

            sum += numR;
            while(left<=right && sum>=k){
                result = Math.min(result, right-left);
                numL = nums.get(left++);
                sum -= numL;
            }
        }

        return result==Integer.MAX_VALUE?-1:result;
    }

    /**
     * 单调栈: 单调增
     * @param nums 整数数组!
     * @param k
     * @return
     */
    private int solution3(ArrayList<Integer> nums, int k){
        int n = nums.size();

        // 前缀和
        long[] preSum = new long[n+1];
        for(int i=1; i<=n; i++){
            preSum[i] = preSum[i-1]+nums.get(i-1);
        }

        int result = Integer.MAX_VALUE;

        Deque<Integer> queue = new ArrayDeque<>();
        for(int i=0; i<=n; i++){
            long curSum = preSum[i];
            // 判断 是否满足条件(>=k)
            while(!queue.isEmpty() && curSum-preSum[queue.peekFirst()]>=k){
                result = Math.min(result, i-queue.pollFirst());
            }
            // 单调栈(单调增)
            while(!queue.isEmpty() && preSum[queue.peekLast()]>=curSum){
                queue.pollLast();
            }
            queue.offerLast(i);
        }

        return result==Integer.MAX_VALUE?-1:result;
    }
}