来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-size-subarray-sum
给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
- 看到题目第一想法就是先判断数组的总和能否大于target值,能的话则按照子序列的长度递增的顺序,找到满足子序列和≥target且长度最短的那个子序列。但是并不知道代码应该如何编写,查看题解,这种办法属于暴力解法,利用两层循环,外层循环用于固定子序列的起点,内层循环用于固定子序列的终点。这样的话能够让数组中的每个元素作为起点,并找到以每个元素为起点的情况下符合要求的第一个子序列。这种方法的时间复杂度为O(n2)。
int minSubArrayLen(int target, int* nums, int numsSize){
int result = INT_MAX;//存储最终的结果
int subLength = 0;//存储子序列的长度
int sum;//存储子序列的和
for(int i = 0; i < numsSize; i++) {
sum = 0;
for(int j = i; j < numsSize; j++) {
sum += nums[j];
if(sum >= target) {
subLength = j - i + 1;
result = result > subLength? subLength : result;
break;
}
}
}
return result == INT_MAX? 0 : result;
}
- 题解的另一种办法是利用滑动窗口。滑动窗口就是利用两个指针,不断调节子序列的起始位置和终止位置,从而得到我们想要的结果。一个指针指向数组的第一个元素用于固定子序列的起点,一个指针用于指向子序列的结尾,以此来调整子序列的长度。滑动窗口感觉就是暴力解法的一种改进,省略了一些必定不满足要求的情况。在暴力解法中,每次子序列的起点改变之后,都是从子序列长度为1的情况出发,找到满足要求的子序列,这其中包括了一些必定不满足要求的情况,我们可以跳过这些情况,那么就能够提高运行速度了。比如,当起点是数组第一个元素的时候,如果找到第一个满足要求的子序列的长度为4,也就是说满足要求的子序列的终点是数组的第四个元素,那么当起点到达数组第二个元素的时候,可以保留上一轮的终点,也就是直接从子序列长度为3的地方开始判断,因为子序列长度为1跟2一定是不满足的,否则终点不会到达4的地方。这种做法的时间复杂度是O(n)
int minSubArrayLen(int target, int* nums, int numsSize){
int result = INT_MAX;//存储最终的结果
int subLength = 0;//存储子序列的长度
int sum = 0;//存储子序列的和
int i =0;//起点
for(int j = 0; j < numsSize; j++) {//终点
sum += nums[j];
while(sum >= target) { //找到该起点下的最短子序列后,起点改变,同时和删去起点值
subLength = j - i + 1;
result = result > subLength? subLength : result;
sum -= nums[i++];
}
}
return result == INT_MAX? 0 : result;
}