您的位置:首页 > 娱乐 > 八卦 > 自己制作网页链接的软件_广州燃气集团有限公司_网络营销的整体概念_百度网站推广关键词怎么查

自己制作网页链接的软件_广州燃气集团有限公司_网络营销的整体概念_百度网站推广关键词怎么查

2025/2/27 9:24:31 来源:https://blog.csdn.net/m0_48241022/article/details/145873350  浏览:    关键词:自己制作网页链接的软件_广州燃气集团有限公司_网络营销的整体概念_百度网站推广关键词怎么查
自己制作网页链接的软件_广州燃气集团有限公司_网络营销的整体概念_百度网站推广关键词怎么查

一、题目简介

题目链接:209. 长度最小的子数组 - 力扣(LeetCode)

给定一个含有 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 <= 109
  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 104

进阶:

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

二、解法

2.1 解法1:暴力解法

两层for循环遍历所有可能。 

// 长度最小的子数组
// [1,1,1,3,3] target=7,返回:3
#include<iostream>
#include<vector>
class solution{public:// 两层for循环,暴力解法int minSubArrayLen(int target, std::vector<int>& nums){   int sum=0; // 子序列的数值之和  int result = INT32_MAX;for(int i=0;i<nums.size();i++){ // 设置子序列的起点为isum=0; // 这块的sum=0必须存在,否则程序运行结果不正确for(int j=i;j<nums.size();j++){ // 设置子序列终止位置为jsum=sum+nums[j]; if(sum>=target){ // 一旦发现子序列和超过了target,更新resultint subLength = j-i+1; // 取子序列的长度 result = result < subLength ? result : subLength; // 判断上一次的result是否小于此次subLength,若小于,则保留上一次的result;如果大于,则把此次的subLength的值赋给result,说明本轮找到的子序列长度要小于上一轮找到的子序列长度break;}}}return result == INT32_MAX ? 0 : result;}
};int main(){solution s1; // 对象实例化int target = 7; // 定义目标值std::vector<int> nums{1,2,3,4,5,6};int SubArraylen = s1.minSubArrayLen(target,nums);std::cout<<"子数组长度为:"<<SubArraylen<<std::endl;return 0;
}

给定数组[1,2,3,4,5,6],目标元素为target=7。

程序开始运行,进入函数内,执行流程为:

i=0,j=0,sum=0-->sum=1<target=7,不进入if判断语句。
i=0,j=1,sum=1-->sum=3<target=7,不进入if判断语句。
i=0,j=2,sum=3-->sum=6<target=7,不进入if判断语句。
i=0,j=3,sum=6-->sum=10>target=7,进入if判断语句,subLength=j-i+1=3-0+1=4,result=subLength=4。
最后执行break语句跳出内层for循环,开始执行外层for下一次循环,有i++,sum=0。

接下来执行流程为:
i=1,j=1,sum=0-->sum=2<target=7,不进入if判断语句。
i=1,j=2,sum=2-->sum=5<target=7,不进入if判断语句。
i=1,j=3,sum=5-->sum=9>target=7,进入if判断语句,subLength=j-i+1=3-1+1=3,result=subLength=3。
最后执行break语句跳出内层for循环,开始执行外层for下一次循环,有i++,sum=0。

接下来执行流程为:
i=2,j=2,sum=0-->sum=3<target=7,不进入if判断语句。
i=2,j=3,sum=3-->sum=7=target=7,进入if判断语句,subLength=j-i+1=3-2+1=2,result=subLength=2。
最后执行break语句跳出内层for循环,开始执行外层for下一次循环,有i++,sum=0。

。。。。。

依此类推,直至遍历完所有的可能。

该方法的时间复杂度与空间复杂度如下: 

  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)

2.2 解法2:滑动窗口法

接下来就开始介绍数组操作中另一个重要的方法:滑动窗口

所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果

在暴力解法中,是一个for循环为滑动窗口的起始位置,一个for循环为滑动窗口的终止位置,用两个for循环完成了一个不断搜索区间的过程。
那么滑动窗口如何用一个for循环来完成这个操作呢。首先要思考如果用一个for循环,那么应该表示滑动窗口的起始位置,还是终止位置。如果只用一个for循环来表示滑动窗口的起始位置,那么如何遍历剩下的终止位置?此时难免再次陷入 暴力解法的怪圈。所以 只用一个for循环,那么这个循环的索引,一定是表示滑动窗口的终止位置。那么问题来了,滑动窗口的起始位置如何移动呢?这里还是以题目中的示例来举例,s=7, 数组是 2,3,1,2,4,3,来看一下查找的过程:

最后找到 4,3 是最短距离。

其实从动画中可以发现滑动窗口也可以理解为双指针法的一种!只不过这种解法更像是一个窗口的移动,所以叫做滑动窗口更适合一些。

在本题中实现滑动窗口,主要确定如下三点:

  • 窗口内是什么?
  • 如何移动窗口的起始位置?
  • 如何移动窗口的结束位置?

窗口就是满足其和 ≥ s 的长度最小的连续子数组。
窗口的起始位置如何移动:如果当前窗口的值大于等于s了,窗口就要向前移动了(也就是该缩小了)。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。

解题的关键在于窗口的起始位置如何移动,如图所示:

 

可以发现滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。 

// 长度最小的子数组
// [1,1,1,3,3] target=7,返回:3
#include<iostream>
#include<vector>
class solution{public:// 滑动窗口法【双指针法】int minSubArrayLen_slideWindow(int target, std::vector<int>& nums){int sum = 0; // 滑动窗口(子序列)数值之和int subLength = 0; // 定义滑动窗口的长度int i=0; // 定义滑动窗口起始位置int result = INT32_MAX;for(int j=0;j<nums.size();j++){sum = sum+nums[j];while(sum>=target){ // 一旦发现子序列和超过了target,更新resultsubLength = j-i+1;result = result<subLength? result:subLength;sum = sum-nums[i]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)i++;}}// 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列return result == INT32_MAX ? 0:result;} };int main(){solution s1; // 对象实例化int target = 7; // 定义目标值std::vector<int> nums{1,2,3,4,5,6};int SubArraylen = s1.minSubArrayLen_slideWindow(target,nums);std::cout<<"子数组长度为:"<<SubArraylen<<std::endl;return 0;
}

给定数组[1,2,3,4,5,6],目标元素为target=7。

程序开始运行,进入函数内,执行流程为:

i=0,j=0,sum=0-->sum=1<target=7,不进入while循环。
i=0,j=1,sum=1-->sum=3<target=7,不进入while循环。
i=0,j=2,sum=3-->sum=6<target=7,不进入while循环。
i=0,j=3,sum=6-->sum=10>target=7,进入while循环。
进入while循环,
subLength=j-i+1=3-0+1=4,result=subLength=4,sum=sum-nums[i],则有:sum=10-->sum=9,随后执行i++语句后,i变为1,j仍然为3。
sum=9依然大于target,再次进入while循环,subLength=j-i+1=3-1+1=3,result=subLength=3,sum=sum-nums[i],则有:sum=9-->sum=7,随后执行i++语句后,i变为2,j还是3。
sum=7等于target,再次进入while循环,subLength=j-i+1=3-2+1=2,result=subLength=2,sum=sum-nums[i],则有:sum=7-->sum=4,随后执行i++语句后,i变为3。
此时sum为4,不符合while循环条件,退出while循环。
经过while循环之后,新的滑动窗口起始位置已经被找出,即i=3。接下来便可进行下一次for循环以更新j的值,随后按照上述流程执行即可。

该方法的时间复杂度和空间复杂度如下:

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

一些录友会疑惑为什么时间复杂度是O(n)

不要以为for里放一个while就以为是O(n^2)啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。

推荐算法解读视频:

拿下滑动窗口! | LeetCode 209 长度最小的子数组_哔哩哔哩_bilibili

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com