【数组】长度最小的子数组
题目:
给定一个含有 n
个正整数的数组和一个正整数 target
。
找出该数组中满足其总和大于等于 target
的长度最小的 子数组 [numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回 0
。
力扣链接:209. 长度最小的子数组 - 力扣(LeetCode)
方法:
滑动窗口
思路:
暴力求解是两个for循环,一个指针在前一个指针在后遍历全部的子数组。用滑动窗口可以压缩成一个for循环:滑动窗口依旧是两个指针,for循环(终止条件:窗口尾指针未抵达数组末尾)控制窗口尾部指针的移动,窗口内的数字之和小于目标值时移动窗口尾指针。for循环内部用一个while循环(终止条件:窗口数字之和小于目标值)控制窗口头部指针的移动,当窗口内数字之和大于等于目标值时,记录此时的窗口长度,并移动窗口头部指针同时更新窗口内数字之和,再次进入while循环,如果此时窗口数字和小于目标值跳出while循环移动窗口尾部指针继续寻找新的满足条件的子数组;反之,如果此时窗口数字之和仍大于等于目标值则再进入while循环尝试压缩窗口大小……直至跳出for循环。
优化点:
暴力求解中,找到满足条件的子数组后,如果尾指针没达到数组尾部,然后向后移动,新得到的这个子数组一定满足条件,但是长度变大不在答案的考虑范围内,属于没用的操作,这个时候可以直接去移动头指针。
代码:
int minSubArrayLen(int target, vector<int>& nums) {int result = INT_MAX;int subLength = 0;//滑动窗口长度int i = 0;//窗口起始位置int sum = 0;//窗口内数字之和for(int j = 0;j<nums.size();j++){sum += nums[j];while(sum >= target)//当窗口内的数之和大于等于target时移动i,尝试寻找其他子数组{subLength = j - i + 1;//此时窗口的长度result = result>subLength?subLength:result;//更新最小子数组长度sum -= nums[i++];//更新窗口数字之和以及移动i}}return result == INT_MAX?0:result;//如果result没有被赋值说明没找到}
时间复杂度:
O(n),每个数字进入和离开一次窗口2*n次操作
空间复杂度:
O(1),没有开辟额外空间