今天刷到一道题,有两种解法:滑动窗口和二分法。同时学到了C++中的一个简化二分的函数low_bound()
请看题
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例2:
输入:target = 4, nums = [1,4,4]
输出:1
示例3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
解法1:滑动窗口
这道题的第一种也是最简便的一种解法就是滑动窗口。左右边界初始分别指向第一个元素。比较此时窗口内的元素和与target的大小,若大于target,左边界++,否则右边界++。
代码如下
int minSubArrayLen(int target, vector<int>& nums) {
int n=nums.size();
int l=0,r=0,count=0,res=INT_MAX;
nums.push_back(0);
while(r<=n){
if(count<target){
count+=nums[r];
r++;
}else{
res=res<(r-l)?res:(r-l);
count-=nums[l];
l++;
}
}
return res==INT_MAX?0:res;
}
解法2:二分法
今天才学到。原来在C++里面二分法其实可以用一个函数low_bound就可以轻易实现,low_bound的底层就是二分法实现的
思路如下:左边界从0到n-1。在左边界不变时。通过二分法找到满足条件的右边界。
代码如下
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size(),ans=INT_MAX;
vector<int> all(n+1);
all[0]=0;
for(int i=0;i<n;i++){
all[i+1]=nums[i]+all[i];
}
for (int i = 1; i <= n; i++) {
int s = target + all[i - 1];
auto bound = lower_bound(all.begin(), all.end(), s);
if (bound != all.end()) {
ans = min(ans, static_cast<int>((bound - all.begin()) - (i - 1)));
}
}
return ans == INT_MAX ? 0 : ans;
}
今天就总结到这儿啦。以后用到二分法时。一定得记住low_bound这个函数的使用哦