一、题目
Given an array of n positive integers and a positive integer s, find the minimal length of a contiguous subarray of which the sum ≥s. If there isn't one, return 0 instead.
For example, given the array [2,3,1,2,4,3]
and s = 7
,
the subarray [4,3]
has the minimal length under the problem constraint.
题意:提供一个有n个数的正整数的数组和一个正整数s,在数组中查找连续最小子数组使得其和大于等于s,返回最小连续子数组的长度
注意:1.首先注意是连续的子数组,两重含义:是原数组的子区间并且是连续的子区间。
2.返回的是子数组的长度,所以存在唯一解。当返回的是连续子数组可能会有无穷多解,注意询问清楚
3.当存在无解的情况返回0
思路:首先设定滑动窗口大小[l...r],当滑动窗口内元素和sum小于s扩大右侧加载一个元素,并再次判断是否大于s,若小于s继续向右加载,若大于s比较更新最短子数组的长度,并在下次循环中减少左侧元素使得窗口能够向右动态滑动。整个过程中滑动窗口的长度是不固定的。
时间复杂度:O(n)
空间复杂度:O(1)
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int l=0,r=-1; //表示滑动窗口的大小[l...r]初始化为无效的
int sum = 0;
int res = nums.size()+1; //记录满足条件的窗口长度,因为是找最小长度,初始值应该是比数组长度大
while(l<nums.size()/*这个条件能自动过滤nums为空的情况*/)
{
if((r+1 < nums.size())/*当有[]操作一定要预防数组越界*/&&sum<s) //当不满足时,滑动窗口向右扩展一位
{
r++;
sum+=nums[r];
}
else
{
sum-=nums[l];
l++;
}
if(sum >= s) //无论向右加载元素还是向左删除删除元素,都需要再次判断是否满足条件比较更新最短的连续子数组长度
{
res=min(res,r-l+1); //r-l+1因为滑动窗口是左右闭区间[l,r]所以需要+1
}
}
if(res == nums.size()+1)
{
return 0;
}
return res;
}
};
当然以上解法如果一时想不到,可以尝试暴力解法,这种解法尽管在leetcode上超时,但是其中部分思想还是可以借鉴的。
预处理:定义了一个vector<int> sums; 这个sums[i]存放的就是[0...i-1]的和,那么求出连续的子区间的和是可以很方便的
[l...r]内元素和等于sums[r+1]-sums[l]。
外围循环遍历所有元素,内层循环就是从l当前元素到最后的元素。
思路就是:挨个查找当前元素和之后的元素间的和是否满足
时间复杂度:O(n^2)
空间复杂度:O(n)
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
// sums[i]存放nums[0...i-1]的和
vector<int> sums(nums.size()+1,0);
for( int i = 1 ; i <= nums.size() ; i ++ )
sums[i] = sums[i-1] + nums[i-1];
int res = nums.size() + 1;
for( int l = 0 ; l < nums.size() ; l ++ )
for( int r = l ; r < nums.size() ; r ++ ){
// 使用sums[r+1] - sums[l] 快速获得nums[l...r]的和
if( sums[r+1] - sums[l] >= s )
res = min( res , r - l + 1 );
}
if( res == nums.size() + 1 )
return 0;
return res;
}
};