力扣209. 长度最小的子数组

题目来源(力扣):

https://leetcode.cn/problems/minimum-size-subarray-sum/description/

题目描述:

给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其总和大于等于 target 的长度最小的 子数组[numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

基本思路:

最基本的算法之一,考察对"滑动窗口"知识的掌握和基础编码能力。
滑动窗口法还会在后面的很多算法题目中遇到~
难点主要是边界left,right更新处理,
《代码随想录中》常用的写法是每一步更新左区间都尝试更新答案,
和《代码随想录》中滑动窗口写法不同,我这里采用的方式是每次更新右区间,满足条件后,继续更新左区间,直到找到当前以右区间为边界的最小的子数组,然后进行一次更新即可;理论上会少很多更新次数,从而优化速率,如下:

代码实现:

class Solution
{
public:
    int minSubArrayLen(int target, vector<int> &nums)
    {
        int ans = nums.size() + 1, l = 0, r = 0;
        int tmp = 0;
        while (l <= r && r < nums.size())
        {
            tmp += nums[r];
            if (tmp >= target)//满足条件
            {
                while (l < r && tmp - nums[l] >= target)//不是每一步都更新ans,而是直接缩短l的位置
                {
                    tmp -= nums[l];
                    l++;
                }
                if (ans > r - l + 1)//然后进行一次更新
                    ans = r - l + 1;
                //tmp -= nums[l];//
                //l++;//这2句可以不写(想想为什么)
            }
            r++;
        }
        if (ans == nums.size() + 1)
            return 0;
        return ans;
    }
};

时间复杂度

O(n),n为数组长度
看似2个while嵌套着,实际上left、right各自都只会从0到n移动,
只不过每次先right移动,当right到合适的位置(这里是移动到某个位置使得子数组的累计和大于了target)时暂停移动,让left移动
然后当left移动到合适的位置(这里是移动到某个位置使得子数组的累计和又小于了target)时暂停移动,让right移动
因此很类似于《操作系统》中进程并发执行的过程~
(怎么样,计算机和神奇吧,各个知识点都是有内在关联的~)

more

如果你还不了解进程并发执行,那建议补充一下《操作系统》的知识
毕竟计算机是一个庞大的体系,算法和数据结构只是其中的一部分,更像是外功
而操作系统、计算机网络等理论知识,是计算机世界的基础成分,类似于内功
内外兼修才能真正成为武林高手

posted @ 2024-10-09 12:11  HB_Computer  阅读(45)  评论(0)    收藏  举报