👏 Hi! 我是 Yumuing,一个技术的敲钟人
👨💻 每天分享技术文章,永远做技术的朝拜者
📚 欢迎关注我的博客:Yumuing's blog
滑动窗口法就是在不断地调整子序列地起始位置与终止位置,从而得出我们想要的结果。滑动窗口法的起始与终止节点的移动的目的即为求解子序列的最优化处理,其基本的思路如下:
- 定义双指针,初始值一致,双指针之间的内容为所谓的窗口,包括双指针所指的元素。
- 确定指针之间的最佳窗口内容的判断条件,即窗口内容扩大、缩小的条件。
- 优先移动终止节点,扩大窗口直至恰好满足判断条件,再移动起始节点一次缩小窗口
- 再次判断是否符合条件,符合,此时为一次所求解的子序列,记录所需参数,继续移动起始节点,不符合,起始节点不动,移动终止节点至恰好符合条件
- 重复第三、第四点,至终止节点到达数组最后一位。
- 输出所需参数
里面最为关键的就是节点的移动,怎么移动!什么时候移动!都是需要根据题目实际情况进行考量。
如果,采取暴力做法采取双层 for 循环方式不断循环寻找符合条件的子序列,时间复杂度为 O(n^2^) ,而如果采用滑动窗口法将减低至 O(n) ,执行效率大大提高。 LeetCode 题目链接:长度最小的数组
题目描述
给定一个含有 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 <= 109
- 1 <= nums.length <= 105
- 1 <= nums[i] <= 105
题目分析
题目简单分析一下,就是获取符合序列内数字之和不小于目标值的最小子序列的长度。思路基本如下:
- 初始化双指针为 0
- 缩小、扩大判断条件确定为 sum >= target
- 利用 for 循环开始右移终止指针,直至符合终止节点到数组最后一位
- 使用 while 循环实现起始指针的不断右移操作,一旦符合条件记录此时长度并与已有记录值比较,取最小值
- 输出长度记录值
class Solution {
// 滑动窗口
public int minSubArrayLen(int s, int[] nums) {
int left = 0;
int sum = 0;
int result = Integer.MAX_VALUE;
for (int right = 0; right < nums.length; right++) {
sum += nums[right];
while (sum >= s) {
result = Math.min(result, right - left + 1);
sum -= nums[left++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
注:
将 result 初始值设置为 int 的最大值是为了方便后面的最小值比较,取零的话,输出结果将会一直为零,只能取最大值。
sum -= nums[left++] 的执行顺序为 sum - = nums[left]; left++;
- 一层 for ,一层 while ,时间复杂度不为 O(n^2^) 的原因为:对于每一个元素来说,while 循环只操作两次,而非 n 次,即 O(2*n) = O(n)