力扣题目链接:209. 长度最小的子数组 - 力扣(LeetCode)
要点:
暴力算法会导致超时,使用滑动窗口解决。
暴力解法:
两个for循环
代码如下:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
if(n == 0){
return 0;
}
int result = Integer.MAX_VALUE;
for(int i = 0; i < n; i++){
int sum = 0;
for(int j = i; j < n; j++){
sum += nums[j];
if(sum >= target){
int sublength = j - i + 1;
result = result < sublength ? result : sublength;
break;
}
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
滑动窗口:
也可以理解为双指针法的一种,通过不断调节子序列的起始位置和终止位置,从而得到我们想要的结果。只用一个for循环,那么这个循环中的索引一定是终止位置。
注意以下三点:
-
窗口内容:满足 和 >= target 的长度最小的连续子数组。
-
窗口起始位置如何移动:通过每次满足 sum >= target 时 让 sum -= nums[i--];也就代表窗口开始缩小了,向前移动了。
-
窗口的结束位置:遍历数组的指针,也就是for循环中的索引。
滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。
代码如下:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int result = Integer.MAX_VALUE;
int sum = 0;
int i = 0;
int subLength = 0;
for(int j = 0; j < nums.length; j++){
sum += nums[j];
while(sum >= target){
subLength = j - i + 1;
result = result < subLength ? result : subLength;
sum -= nums[i++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
-
时间复杂度:O(n)