长度最小的子数组
题目链接
思路
看到这道题我其实懵的一下,以为这个字串不连续。
仔细读题后,才发现是连续,这个条件让暴力变得非常直观,且简单
暴力法直接两个循环,类似冒泡一样,每次外循环记录一次子数组长度。
如果这次外循环的数组之和大于等于val值,则进行一次长度值的比较,这个值小于之前存的最小长度则更新,不小于不更新。很直观是吧,但还是有点low
让我们换个思路,想一想,这个目标最小长度值的数组是连续的。我们从数组的第一个值开始考虑,这个值单独的和不够大,只有一条路可走,那就是加上它的下一个值。因为目标数组是连续的嘛。加上下一个不够就就再加,直到恰好等于或者大于。
等于的时候,说明这个满足等于条件,但不一定最小,所以要把它和存的最小值比较(初试最小值默认非常大),小于最小值则更新,和暴力差不多对吧。当然也别忘了继续减去子数组的第一个数,我们还要继续找,不是吗?当然,加上子数组的下一个数也是一样的,可以自己推理一下。
大于的时候,我们不能再往回退了对吧,那样就重了。我们只能去掉第一个数,因为是连续的嘛,单独去掉第二个就不连续了。而且再加上一个数的长度就一定不是最小的了,所以虽然再加上下一个值满足条件,但一定不是最小的,所以之后的都不要了。有意思吧,就像个窗口一样,向右滑动。
小于就加上数组的下一个数,大于就减去数组的前一个数,这样的搜索法是不是很高级,哈哈哈。
暴力法
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int result = INT32_MAX;
for(int i=0;i<nums.size();i++){
int sum=0;
for(int j=i;j<nums.size();j++){
sum+=nums[j];
int sublength = j-i+1;
if(sum>=s){
result = result < sublength ? result : sublength;
break;//因为这个满足条件,其后一定满足但都不是目标值。所以进行下一次的外循环。
}
}
}
return result == INT32_MAX ? 0 : result;
}
};
这个代码仅能通过测试,提交时会超时,但结果没有问题。换句话说,效率太low了。
滑动窗口法
代码如下:
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int result = INT32_MAX;//INT32_MAX是一个很大的数,多大我也不清楚,反正就是目前够你用的大。
int sum = 0; //窗口数值之和,由于全局参与且每次都可能更新,所以在所有循环外定义。
int i = 0; //这个用于指向起始位置
//问我为什么j是定义在循环里的,因为j一定会到大原数组末尾,但i不一定,i类似一个慢指针。
int subLength = 0;//用于记录每次的长度,并于result进行比较
for (int j = 0; j < nums.size(); j++) {
sum += nums[j];
while (sum >= s) {
subLength = (j - i + 1);//提取数组长度,小学的逻辑题,别告诉我你不懂。
result = result < subLength ? result : subLength;//正确:左边,错误取:右边。注意符号是英文的。
sum -= nums[i++];//i++和++i分别是语句执行完后加1和执行之前加1,当然,我指的是本行语句。
}
}
// 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
return result == INT32_MAX ? 0 : result;
}
};