题目链接
整体思路
我首先想到的解答方法是采用滑动窗口,题目底部提到使用O(nlogn)的方法去解决,所以又想了第二种解答方法,即进行累加再采用二分的方法查找。
详细解答
1.滑动窗口的方法
先取l=0,r=0,然后l不变,r向右滑动直到[l,r)区间的数字之和sum>=target(若不存在则答案为0),此时我们可以得到以l为下限得到的最小答案。然后将l右滑,r固定,直到sum-nums[l]<target,此时我们又可以得到一个答案,将目前得到的答案和之前的答案进行比较,取最小值,不断重复上述步骤,直到所有r>=nums.length。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int l=0,r=0;
int sum=0;
int ans=nums.length+1;
while (r<nums.length){
while(sum<target&&r<nums.length)
sum+=nums[r++];
if(sum>=target)
ans=Math.min(ans,r-l);
while (sum>=target&&l<r){
sum-=nums[l++];
if(sum>=target)
ans=Math.min(ans,r-l);
}
}
if(ans==nums.length+1)
ans=0;
return ans;
}
}
2.遍历+二分的方法
注意到数组中的所有值都是正整数,所以对数组进行累加就可以得到一个递增的数组。以每个数字为子区间最左边的数字,采用二分查找的方法得到以该数字为下限的最小子区间即可,取遍历得到的最小子区间长度为答案。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int l,r;
int ans=nums.length+1;
for(int i=1;i<nums.length;i++)
nums[i]+=nums[i-1];
for(int i=0;i<nums.length;i++){
l=i;
r=nums.length-1; //左闭右闭
int presum=i==0?0:nums[i-1];
int sum=0;
while(l<=r) {
int m=(l+r)/2;
sum=nums[m]-presum;
if(sum<target)
l=m+1;
else if(sum==target) {
l=m;
break;
}
else
r=m-1;
}
if(sum>=target)
ans=Math.min(ans,l-i+1);
}
if(ans==nums.length+1)
ans=0;
return ans;
}
}