Leetcode Link:长度最小的子数组
代码随想录:超详解
题目原文
给定一个含有 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 <= 10^91 <= nums.length <= 10^51 <= nums[i] <= 10^4
分析
- 常规暴力法思路为“起点前移,确定起点,终点遍历数组直到加和
sum符合条件”,时间复杂度O(n^2)。 - 数组元素全为正整数,数据量大:如果限时严苛,暴力法可能会超时;加和是单调递增的,一直加一直增。
- 返回最小子数组的长度值,可能不存在满足条件的解:判断逻辑要清晰。
题解与要点
class Solution
{
public:
int minSubArrayLen(int target, vector<int> &nums)
{
int result = 2147483647; //要点一
for (int begin = 0, end = 0, sum = 0, length = 0; end < nums.size(); end++)//要点二
{
sum += nums[end];
while (sum >= target)
{
length = end - begin + 1;//要点三
if (length < result)
{
result = length;
}
sum -= nums[begin];//要点四
begin++;
}
}
if (result == 2147483647)//要点五
{
return 0;
}
else
{
return result;
}
}
};
要点解析
要点一:根据题目给定的数据范围1 <= nums.length <= 10^5,求解结果result应当先设定为一个不小于nums.length的值,然后逐步缩小。int类型的取值范围为-2,147,483,648 (-2³¹) ~ 2,147,483,647 (2³¹-1)。此外,result的scope应当设置为整个类,防止循环后重置。
要点二:此处将循环条件设定为子数组终点end而非起点begin的原因是,“起点递增加一之后,终点也遍历递增向前”这种思路,和未使用索引指针的暴力法同源,时间复杂度仍旧是O(n^2)。
若将终点设为循环条件并一直向前,起点可以在递加和sum符合条件后有限度地前移而非遍历。对于数组内每个元素来说,至多只会被读取两次(起点和终点的指针各读取一次),时间复杂度为O(n)。
要点三:区间长度要记得+ 1,和小学植树问题同理。
要点四:这两句可以合并为sum -= nums[begin++],在起点前移的同时删除不再处于区间内的值。
要点五:判断是否有满足题目条件的结果,并返回相应的值。
413

被折叠的 条评论
为什么被折叠?



