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

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

写在前面:


算法小白,想通过每日一题+博客记录的形式来督促自己提升,在此过程中肯定会有诸多问题,欢迎各位大佬批评指正,我们山顶见!!


---------------------------------------------------------------------------------------------------------------------------------


正文开始:


题目:


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

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


示例:8eb14bcbbbbd44689e43f3b98395af36.png


思考过程:


      题意理解:   将一个连续的子数组中的每一个元素相加,若结果等于k,则返回这样的子数组的最短长度,若无这样的非空子数组,则返回-1;


       题中出现连续的子数组相加,则考虑用前缀和方法处理初始数据。


        n=nums.size();
        vector<int>s(n+1,0);
        for (int i = 1; i <= nums.size(); i++)
        {
            s[i] = s[i-1] + nums[i-1];
        }


先创建一个长度为n(nums.size())+1的数组s,初始化为0;


小问答:为何为n+1呢?


               因为前缀和数组是s[i]=s[i-1]+nums[i-1];


               当i=1时,s[1]=s[0]+nums[0];所以若s的长度=nums长度+1


此时s[i]-s[j]=nums[j+1]++.....+nums[i] 我们想要的子数组模型不就出来了嘛;


当s[i]-s[j]>=k时不就是我们要的答案嘛? 但这是理想化的,因为这个nums数组可能有正有负,s可能是一个不单调的数组,


若is[j] 若s[t]-s[i]可以>=k那s[t]-s[j]同样也可以>=k;


减数越小,差值越大


且j是距离t更近的数,是一个更优的解,所以我们更需要的是这个j而不是这个i;


需要将之前存入的i(因为i


根据我们的需求来看,我们需要定义一个双端队列来处理这个问题;


         deque<int> de;
        de.push_back(0);


小问答:


       为什么需要push_back(0);


       因为初始化队列,让接下来的相减有一个初始的减数


此时de队列第一个数为0


 while (de.size() && s[i] <= s[de.back()])
                de.pop_back();


若is[j] 若s[t]-s[i]可以>=k那s[t]-s[j]同样也可以>=k;


减数越小,差值越大,且j是距离t更近的数,是一个更优的解,所以我们更需要的是这个j而不是这个i,同时也为了让比较的队列成为单调递增的队列


需要将之前存入的i(因为i思考下为什么?


接下来完成我们题解最重要的一步进行条件判断


       当s[i]-s[队列中的第一个数]>=k时,我们先更新一下最优解,之后再将队列中的第一个数移除


      为什么要将第一个数移除呢?


       因为s[i]-s[first]已经满足了条件,之后的队列都不会用到first了,当i增加时他已经不需要去跟first比较,因为相减就算满足条件,这时候也不是最优解。我们没必要再去用到它


 while (de.size()&&s[i]-s[de.front()]>=k)
            {
                ans = min(ans,i-de.front());
                de.pop_front();
            }


做完这一切之后,我们将刚刚的i插入到我们的单调队列de中


            de.push_back(i);


至此我们的函数主体已经讲完,具体实现如下


class Solution {
public:
    int shortestSubarray(vector<int>& nums, int k)
    {
        int n=nums.size();
        int ans=n+1;
        vector<long long> s(n+1,0);
        for (int i = 1; i <= n; i++)
        {
            s[i] = s[i-1] + nums[i-1];
        }
        deque<int> de;
        de.push_back(0);
        for(int i=1;i<=n;i++)
        {
            while (de.size()&&s[i]-s[de.front()]>=k)
            {
                ans = min(ans,i-de.front());
                de.pop_front();
            }
            while (de.size() && s[i] <= s[de.back()])
                de.pop_back();
            de.push_back(i);
        }   
        return ans==n+1?-1:ans;
    }
};


 本文代码及思想参考:【力扣(LeetCode) 每日一题 单调队列 862. 和至少为 K 的最短子数组 - 2022-10-26】


‘克拉克黎明之前’大佬对我的帮助很大,本文仅以记录学习为目的,无任何其他想法,若侵权可联系我删除


——————————————————————————————————————————


写在后面:


第一篇真正意义的博客至此结束了,本来我认为写博客完全没啥意义,但在完成这一篇的过程中,发现很多之前自己没有考虑到的问题,在这过程中学到了很多。因为是第一篇博客,在排版,语言等方面还略显青涩,请多多包涵。未来我也会在博客方面多多提升自己,争取产生出更多优质内容,一起进步,我们山顶见!


目录
相关文章
|
1月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
38 0
|
3月前
|
算法
LeetCode第53题最大子数组和
LeetCode第53题"最大子数组和"的解题方法,利用动态规划思想,通过一次遍历数组,维护到当前元素为止的最大子数组和,有效避免了复杂度更高的暴力解法。
LeetCode第53题最大子数组和
|
3月前
|
存储 Java API
LeetCode------合并两个有序数组(4)【数组】
这篇文章介绍了LeetCode上的"合并两个有序数组"问题,并提供了三种解法:第一种是使用Java的Arrays.sort()方法直接对合并后的数组进行排序;第二种是使用辅助数组和双指针技术进行合并;第三种则是从后向前的双指针方法,避免了使用额外的辅助数组。
LeetCode------合并两个有序数组(4)【数组】
|
3月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
113 2
LeetCode------找到所有数组中消失的数字(6)【数组】
这篇文章介绍了LeetCode上的"找到所有数组中消失的数字"问题,提供了一种解法,通过两次遍历来找出所有未在数组中出现的数字:第一次遍历将数组中的每个数字对应位置的值增加数组长度,第二次遍历找出所有未被增加的数字,即缺失的数字。
|
3月前
|
前端开发
LeetCode------移动零(5)【数组】
这篇文章介绍了LeetCode上的"移动零"问题,提出了一种使用双指针的原地操作解法,该方法首先将非零元素移动到数组前端并保持相对顺序,然后填充后续位置为零,以达到题目要求。
|
1月前
【LeetCode-每日一题】 删除排序数组中的重复项
【LeetCode-每日一题】 删除排序数组中的重复项
19 4
|
1月前
|
索引
Leetcode第三十三题(搜索旋转排序数组)
这篇文章介绍了解决LeetCode第33题“搜索旋转排序数组”的方法,该问题要求在旋转过的升序数组中找到给定目标值的索引,如果存在则返回索引,否则返回-1,文章提供了一个时间复杂度为O(logn)的二分搜索算法实现。
18 0
Leetcode第三十三题(搜索旋转排序数组)
|
1月前
|
算法 C++
Leetcode第53题(最大子数组和)
这篇文章介绍了LeetCode第53题“最大子数组和”的动态规划解法,提供了详细的状态转移方程和C++代码实现,并讨论了其他算法如贪心、分治、改进动态规划和分块累计法。
56 0
|
1月前
|
C++
【LeetCode 12】349.两个数组的交集
【LeetCode 12】349.两个数组的交集
16 0