长度最小的子数组
题意:
找到一个长度最小的子串,使得子串的和大于等于给定的s。
像这种子串最优解的问题,很多时候都可以用滑动窗口。此题用Sliding window 也是最明显的。
class Solution {
public:
int minSubArrayLen(int s, vector<int>& a) {
int ans = 1e9,n = a.size();
int l = 0 ,r = 0 ,cnt = 0;
while(l<n){
while(r<n && cnt<s){
cnt += a[r++];
}
if(cnt>=s) ans = min(ans,r-l);
cnt -= a[l];
l++;
}
return ans==1e9?0:ans;
}
};
如果用纯暴力法呢?
那就应该是枚举每一个位置作为子串的起点,然后挨个向后枚举,看看最近的终点在哪,(可以使得子串和大于等于s)?
由于题目给定所有的数都是正整数,所以完全可以二分查找最小的
,使得,对于枚举的
,使得
。
整体时间复杂度:
class Solution {
public:
int minSubArrayLen(int s, vector<int>& a) {
int ans = 1e9 , n = a.size();
vector<int> pre(n);
if(n==0) return 0;
pre[0] = a[0];
for(int i=1;i<n;i++){
pre[i] = pre[i-1]+a[i];
}
for(int i=0;i<n;i++){
if((i==0 && pre[n-1]<s)|| (i && pre[n-1]-pre[i-1]<s)){continue;}
int l = i,r = n-1;
while(l<r){
int mid = (l+r)/2 ,sum;
if(i) sum = pre[mid]-pre[i-1];
else sum = pre[mid];
if(sum<s){
l = mid+1;
}else{
r = mid;
}
}
ans = min(ans,l-i+1);
}
return ans==1e9?0:ans;
}
};