方法1:用双指针滑动窗口。这是一种双指针应用类型题。复杂度O(n)。
class Solution {
public:int minSubArrayLen(int s, vector<int>& nums) {
int len=nums.size();
if(len==0) return 0;
int left=0,right=0;
int MinLength;
int sum=0;
for(int i=0;i<len;i++){
sum+=nums[i];
if(sum>=s) break;
}
if(sum>=s) MinLength=len;
else return 0;
sum=0;
int new_length=0;
while(left<len){
while(right<len && sum<s){
sum+=nums[right];
right++;
}
new_length=right-left;
if(sum>=s && MinLength>new_length){
MinLength=new_length;
}
sum-=nums[left];
left++;
}
return MinLength;
}
};
方法2:二分法。时间复杂度O(N*logN)
思路:
网上说的一个思路:建立一个比原数组长一位的sums数组,其中sums[i]表示nums数组中[0, i - 1]的和,然后我们对于sums中每一个值sums[i],用二分查找法找到子数组的右边界位置,使该子数组之和大于sums[i] + s,然后我们更新最短长度的距离即可。
自己当时用的唯一不同是sums数组并没有比原来长一位,sums[i]表示sums数组中[0,i]的和。
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int len=nums.size();
if(len==0) return 0;
int MinLength;
int sum=0;
//如果所有的值加起来都小于s,就没有继续下去的必要了
for(int i=0;i<len;i++){
sum+=nums[i];
if(sum>=s) break;
}
if(sum>=s){
MinLength=len;
}else{
return 0;
}
//前面所有元素累加的数组
int* all=new int[len];
all[0]=nums[0];
for(int i=1;i<len;i++){
all[i]=all[i-1]+nums[i];
}
//以第一个元素作为左边界,确定大于s的最小右边界
int left=0,right=len-1;
int mid;
if(all[right]<s){
delete []all;
return 0;
}
while(left<right){
mid=(left+right)/2;
if(all[mid]<s){
left=mid+1;
}else{
right=mid;
}
}
if(MinLength>right-0+1){
MinLength=right-0+1;
}
//以第当前元素作为左边界,确定大于s的最小右边界
for(int i=1;i<len;i++){
left=i,right=len-1;
if(all[right]-all[left-1]<s) continue;
while(left<right){
mid=(left+right)/2;
if(all[mid]-all[i-1]<s){
left=mid+1;
}else{
right=mid;
}
}
if(MinLength>right-i+1){
MinLength=right-i+1;
}
}
delete []all;
return MinLength;
}
};