862. 和至少为 K 的最短子数组(困难)-前缀和单调双端队列

Posted hequnwang10

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了862. 和至少为 K 的最短子数组(困难)-前缀和单调双端队列相关的知识,希望对你有一定的参考价值。

一、题目描述

给你一个整数数组 nums 和一个整数 k ,找出 nums 中和至少为 k 的 最短非空子数组 ,并返回该子数组的长度。如果不存在这样的 子数组 ,返回 -1 。

子数组 是数组中 连续 的一部分。

示例 1:
输入:nums = [1], k = 1
输出:1
示例 2:
输入:nums = [1,2], k = 4
输出:-1
示例 3:
输入:nums = [2,-1,2], k = 3
输出:3

二、解题

前缀和+单调双端队列

这题如果是全是正数,就好做了,使用滑动窗口,先固定右边界,然后移动左边界,直至找到最小的窗口,但是这题出现负数,当窗口含有负数值时,窗口会变大,所以需要使用前缀和单调双端队列来实现。记录每个下标的前缀和sum。然后使用一个队列:

  • 当前下标元素的前缀和-队头下标的前缀和>=K,队头弹出
  • 当前下标元素的前缀和小于队尾下标元素的前缀和,队尾弹出,因为后面的前缀和-前面的前缀和的差值>k,保证队列长度是最小值。
class Solution 
    public int shortestSubarray(int[] nums, int k) 
        //最短非空子数组的长度 
        
        // 1.当前元素-队头>=K,队头弹出
        // 2.当前元素小于队尾,队尾弹出
        int length = nums.length;
        long[] sum = new long[length+1];
        for(int i = 1;i<=length;i++)
            sum[i] = sum[i-1]+nums[i-1];
        
        Deque<Integer> queue = new LinkedList<>();
        int res = length+1;
        for(int i = 0;i <= length;i++)
            //当前元素小于队尾,队尾弹出
            while(!queue.isEmpty() && sum[i] <= sum[queue.peekLast()])
                queue.removeLast();
            
            //当前元素-队头>=K,队头弹出
            while(!queue.isEmpty() && sum[i] - sum[queue.peek()] >= k)
                res = Math.min(res,i-queue.removeFirst());
            
            queue.addLast(i);
        
        return res == length+1 ? -1 : res;       
    

时间复杂度:O(n);

空间复杂度:O(n)。

以上是关于862. 和至少为 K 的最短子数组(困难)-前缀和单调双端队列的主要内容,如果未能解决你的问题,请参考以下文章

力扣 每日一题 862. 和至少为 K 的最短子数组难度:困难,rating: 2306(前缀和+单调队列)

⭐算法入门⭐《队列 - 单调队列》困难03 —— LeetCode 862. 和至少为 K 的最短子数组

LeetCode 862 和至少为K的最短子数组[前缀和 双端队列] HERODING的LeetCode之路

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

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

和至少为K的最短子数组