【LeetCode每日一题】长度最小的子数组
标签:
二分,前缀和,滑动窗口,双指针
- 前缀和&二分
target要大于等于子数组nums[l]到nums[r]这段连续区间的和,因此想到用前缀和sums[r]-sums[l-1]可以快速求得区间和。
如何寻找target呢,要寻找sums[r]-sums[l-1]>=target,移项得sums[r]>=target+sums[l-1],也就是在数组中寻找sums[r]这样得数,使他大于等于target+sum[l-1]。
如何快速查找,因为前缀和数组是递增数组,可以使用二分查找
class Solution {
public:
int binary_serach(int t,int l,int r,vector<int>&sums)
{ int mid;
while(l<=r)
{
mid=(l+r)>>1;
if(sums[mid]>=t)r=mid-1;
else l=mid+1;
}
if(sums[l]>=t)return l;
return 0;
}
int minSubArrayLen(int target, vector<int>& nums) {
int ans=INT_MAX;
int n=nums.size();
if(n==0)return 0;
int l,r;
vector<int>sums(n+2,0);//开一个大一点得vector数组,因为这里使用前缀和数组用1开始做下标
for(int i=1;i<=n;i++)sums[i]=sums[i-1]+nums[i-1];//前缀和
for(int i=1;i<=n;i++)
{
int t=target+sums[i-1];//寻找sums[r]-sums[l-1]>=target,转化为寻找sums[r]>=sum[l-1]+target
l=0,r=n;
int x=binary_serach(t,l,r,sums);
if(x)ans=min(ans,x-(i-1));
}
if(ans==INT_MAX)return 0;
return ans;
}
};
-
双指针&滑动窗口
设置两个指针i和j,j一直向右移动,i符合条件才移动
因为是寻找长度最小的子数组,当sum>=target时,记录长度,然后i要向右移动,当sum<target时j继续移动,寻找下一个sum>=target的条件
class Solution { public: int minSubArrayLen(int target, vector<int>& nums) { int n=nums.size(); int ans=INT_MAX; long long sum=0; for(int i=0,j=0;j<n;) { sum+=nums[j]; while(sum>=target) { ans=min(ans,j-i+1); sum=sum-nums[i]; i++; } j++; } if(ans==INT_MAX)return 0; return ans; } };
网友的理解方式通俗易懂