CC52.【C++ Cont】滑动窗口

目录

1.题目

2.分析

方法1:暴力枚举

方法2:暴力枚举的优化:"同向双指针",也称滑动窗口

前置知识

核心操作

例子解释

代码

提交结果


1.题目

LCR 008. 长度最小的子数组

给定一个含有 n个正整数的数组和一个正整数 target。

找出该数组中满足其和≥ target的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度**。** 如果不存在符合条件的子数组,返回 0 。

示例 1:

复制代码
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:

复制代码
输入:target = 4, nums = [1,4,4]
输出:1

示例 3:

复制代码
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

提示:

  • 1 <= target <= 10^9
  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^5

进阶:

  • 如果你已经实现O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。

注意:本题与主站 209 题相同:209. 长度最小的子数组 - 力扣(LeetCode)

2.分析

方法1:暴力枚举

第一层循环:枚举连续子数组的长度len,从1到nums.size()

第二层循环:对于每个len,可能有多个子数组,按子数组首元素的下标来枚举

第三层循环:计算子数组中元素的和,如果找到一个sum>=target,直接返回len

时间复杂度为

以2,3,1,2,4,3为例分析:

len==1: 2,3,1,2,4,3

len==2: 2,3,3,1,1,2,2,4,4,3

len==3: 2,3,1,3,1,2,1,2,4,2,4,3

len==4: 2,3,1,2,3,1,2,4,1,2,4,3

len==5: 2,3,1,2,4,3,1,2,4,3

len==6: 2,3,1,2,4,3

cpp 复制代码
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) 
    {
        for (int len=1;len<=nums.size();len++)
        {
            for (int i=0;i+len<=nums.size();i++)
            {
                //计算子数组的和
                unsigned long long sum=0;
                for (int j=i;j<i+len;j++)
                    sum+=nums[j];
                if (sum>=target)
                    return len;
            }
        }
        return 0;
    }
};

提交结果:代码的时间复杂度为,显然当数据量较大时会超时

方法2:暴力枚举的优化:"同向双指针",也称++滑动窗口++

前置知识

给定闭区间left,right,left为区间左边界,right为区间的右边界

由于题目给出"给定一个含有 n个正整数的数组",数组中元素都是正整数,则right变大时,区间的元素和也变大 ,则可以利用++区间的元素和的单调性++写"滑动窗口",这样就规避掉方法1没有必要的枚举行为

核心操作

将left,right之间连续的元素视为窗口

进窗口:right++,让新元素进入窗口

出窗口:left++,让旧元素离开窗口

例子解释

在遍历的同时去求和,类似前缀和思想,仍然以2,3,1,2,4,3,target = 7为例说明:

设len存储返回值,left给出左边界,将left固定,right从左边界向后枚举,right每指向一个新数,就为sum加上这个新数(思想类似前缀和,比方法1每次循环重新计算一遍sum要快)

一开始各个变量的初始值:

cpp 复制代码
int left=0;
int right=0;
int sum=nums[0];
int len=10001;

注:len初始化为10001的原因:题目"1 <= nums.length <= 10^5",len设置成比nums.length稍大的数就行了

(红色区域为滑动窗口)

如果sum<target,right++,为"进窗口"(新数据进入窗口),同时sum加上对应的值

cpp 复制代码
if (sum<target)
{
    right++;
    if (right==nums.size())
        break;
    sum+=nums[right];
}

此时sum>target,记录len的值:right-left+1==4,但这个len不一定是最小值,因此要继续"滑动"窗口

注意:此时没有必要继续right++,因为sum已经大于target,题目要求最小值

left++,为"出窗口"(移除旧数据)sum减去对应的值,注意right不用回退,要利用**++区间的元素和的单调性++**

cpp 复制代码
if (sum>=target)
{
    len=min(len,right-left+1);
    sum-=nums[left];
    left++;
}

sum<target,"进窗口"

sum>target,窗口长度为4,取len=min(len,right-left+1),之后"出窗口"

sum>target,窗口长度为3,取len=min(len,right-left+1),之后"出窗口"

sum<target,"进窗口"

sum>target,窗口长度为3,取len=min(len,right-left+1),之后"出窗口"

sum==target,窗口长度为2,取len=min(len,right-left+1),之后"出窗口"

sum<target,但right已经到头了,因此结束循环,返回len,则可得出循环的框架:

cpp 复制代码
while (right<nums.size())
{
    //do_something
}

"同向双指针":left和right向同一个方向移动

时间复杂度:right最多移动到nums.size()-1处,时间复杂度为

代码

cpp 复制代码
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) 
    {
        int left=0;
        int right=0;
        int sum=nums[0];
        int len=100001;
        while (right<nums.size())
        {
            if (sum<target)
            {
                right++;
                if (right==nums.size())
                    break;
                sum+=nums[right];
            }
            else//sum>=target
            {
                len=min(len,right-left+1);
                sum-=nums[left];
                left++;
            }
        }
        if (len==100001)
            return 0;
        else
            return len;
            
    }
};

提交结果

相关推荐
ebiobiz6 分钟前
极海 APM32 使用 Nimmake 编译指南
c++·python·单片机·嵌入式硬件·mcu
青山木8 分钟前
Hot 100 --- 编辑距离
java·数据结构·算法·leetcode·动态规划
朝朝辞暮i8 分钟前
C++ 第 26 课:对象、指针与 ->
java·开发语言·c++
夊39 分钟前
C语言第十一课:指针(五)
算法
2601_9628857240 分钟前
如何用 Python 做股价历史分位选股?(筛出处于历史低位的股票)
开发语言·python
小师兄吃牛肉40 分钟前
C语言指针进阶全解析
java·c语言·算法
梦帮科技1 小时前
vLLM / TensorRT-LLM 极限推理:PagedAttention 细粒度物理页表管理与连续批处理(Continuous Batching)实战
数据结构·人工智能·分布式·python·深度学习·算法·vllm
殷色玫瑰1 小时前
C++入门基础复习:从命名空间到引用与nullptr,一篇重新捡回C++基础
java·开发语言·c++
(Charon)1 小时前
【C++面试】手写线程池:任务队列、工作线程与优雅退出
开发语言·c++
言乐62 小时前
Python概括后端原理
开发语言·python·django·virtualenv·pygame