题目描述
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
本题思路
暴力解法
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int result = INT32_MAX; // 最终的结果
int sum = 0; // 子序列的数值之和
int subLength = 0; // 子序列的长度
for (int i = 0; i < nums.size(); i++) { // 设置子序列起点为i
sum = 0;
for (int j = i; j < nums.size(); j++) { // 设置子序列终止位置为j
sum += nums[j];
if (sum >= s) { // 一旦发现子序列和超过了s,更新result
subLength = j - i + 1; // 取子序列的长度
result = result < subLength ? result : subLength;
break; // 因为我们是找符合条件最短的子序列,所以一旦符合条件就break
}
}
}
// 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
return result == INT32_MAX ? 0 : result;
}
};
代码是从代码随想录复制过来,没有自己打过。这需要反思,不能因为是暴力就忽视。
滑动窗口
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) { // 滑动窗口
int sum = 0;
int i = 0,j;
int result = INT32_MAX;
for (j = 0; j < nums.size(); j++) {
sum += nums[j];
while (sum >= target) {
int s = j - i + 1;
result = min(result, s);
sum -= nums[i];
i++;
}
}
return result == INT32_MAX ? 0 : result;
}
};
这个是自己纯手工打了很多遍的代码。
个人见解
j表示的是子串的末尾位置,i表示的是子串的起始位置。
第一理解
可能不太严谨个人理解,如有错误还望指出!
- 滑动窗口只枚举了最有可能的几个解,首先是以第一个字符为首的字符串开始寻找,直到总和大于目标.那么再往后找就以无意义,不再是最小子数组
- 记录当前的子数组长度
- 接着将滑动窗口起始指针向后移动(因为包含起始位置元素的子数组可能不是最小子数组,所以滑动窗口起始指针移动,比较其后的子数组是否为满足条件的子数组)
- 满足则更改记录的数据
- 如果没有更改原本的数据即为没有满足的条件
第二理解
例如 abcde 代表不同数字
外层循环 先不看i的移动
- a
- ab
- abc
- abcd
- abcde
前一次所遍历的字符串都为后一次的子串,假如bc为外层循环第三次得到的第一个结果,那么第四次i就无需再从abcd考虑,直接考虑bcd是否还有更短的子串。解释i不重置的问题,同样也是这题的主要思想