题型描述
在我们学习算法的过程中,有一种操作数组种经典的题型,给出一个数组,要求找出数组中最小或最大的子数组,该数组满足题目给出的一个限定条件。如下题--leetcode题号209
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例:
- 输入:s = 7, nums = [2,3,1,2,4,3]
- 输出:2
- 解释:子数组 [4,3] 是该条件下的长度最小的子数组。
提示:
- 1 <= target <= 10^9
- 1 <= nums.length <= 10^5
- 1 <= nums[i] <= 10^5
算法公开课
解题思路
弯路:可能新入门的小白们的第一想法都是采用暴力解法,利用两层for循环,对数组里的所有数字排列组合进行遍历,这样不仅效率极其的慢,而且在leetcode上也无法通过,这样操作它的时间复杂度为O(n^2)
这时候就要引入我们的滑动窗口思路...
滑动窗口的核心思想是设立一个可变长度的窗口,该窗口能在原数组上左右滑动,每次滑动时,窗口内元素组成的目标集合随之变化,从而高效地解决一系列问题。窗口的移动通常伴随着元素的加入和移除,而窗口的大小(即包含元素的数量)可以根据具体问题灵活调整。在此处我们仅需要用一个for循环就能完成操作。如下图所示--取用代码随想录中的图片
实现
这样我们只要把for循环用i来遍历,每一次for循环完成,i++,j只要在不满足要求时向前不断前进,直到满足条件---->因为不满足条件时要不断前进,所以j的操作要在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;
}
}
总结
滑动窗口技术以其灵活性和高效性,在处理数组相关问题时展现出强大的威力。但是滑动窗口并不难理解,在面对数组操作连续的子数组时,滑动窗口能够派上用场,并且滑动窗口都能提供简洁优雅的解决方案。掌握这一技巧,不仅能提高算法题目的解题效率,更能深刻理解数据结构和算法之美。在未来的学习与实践中,不妨多思考滑动窗口的应用场景,让它成为你解决问题的得力工具。