LeetCode 209:长度最小的子数组
解法
解法一:滑动窗口
想法不难,主要比较一下自己的实现方法和标准的实现方法之间的区别
// mine
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int minlen=1e5+5, left=0, right=-1, sum=0;
// 如果一开始设置right=0, sum=nums[0], 也行
while(1){
if(sum < target){
right++;
// 这里要进行一个判断,如果right到了最右端,nums[++right]会越界
if(right == nums.size()) break;
else sum += nums[right];
}
else{
minlen = min(minlen, right-left+1);
sum -= nums[left++];
}
}
if(minlen == 1e5+5) return 0;
else return minlen;
}
};
// standard
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n=nums.size(), s=0, Min=INT_MAX;
for(int l=0,r=0;r<n;r++){
s += nums[r]; // 滑动窗口总和加上右边界数
while(s >= target){ // 滑动窗口总和≥目标值
Min = min(Min, r-l+1); // 最小区间=min(最小区间, 滑动窗口长度)
s -= nums[l++]; // 滑动窗口总和减去左边界数,左边界右移
}
}
return (Min==INT_MAX) ? 0 : Min;
}
};
//不要以为for里放一个while就以为是O(n^2)啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被被操作两次,所以时间复杂度是 2 × n 也就是O(n)。
另一个想法:每次迭代中只缩小或者平移窗口,从不扩大窗口,这样不需要去维护一个历史最小窗口的min值,性能得以提升
解法二:前缀和+二分
核心代码:
数组中每个元素都为正,所以前缀和一定是递增的,这一点保证了二分的正确性。