🍐滑动窗口的概念
🍐滑动窗口算法也是一种思想
,是双指针的拓展和延伸
。 🍊 滑动
:说明这个窗口是移动的,也就是移动是按照一定方向来的。
🍊 窗口
:窗口大小并不是固定的,可以不断扩容直到满足一定的条件;也可以不断缩小,直到找到一个满足条件的最小窗口;当然也可以是固定大小。
🍏适用场景
🍏 滑动窗口主要应用在数组和字符串上 ,在一个特定大小的字符串或数组上进行操作,而不在整个字符串和数组上操作,这样就降低了问题的复杂度,从而也达到降低了循环的嵌套深度。
🍋 什么情况适合用滑动窗口来解决实际问题呢?
🍒 一般给出的数据结构是数组或者字符串。
🍒 求取某个子串或者子序列最长最短等最值问题或者求某个目标值时。
🥑题目示例
题目:长度最小的子数组
题目描述:
给定一个含有n个正整数的数组和一个正整数target 。
找出该数组中满足其和≥target的长度最小的连续子数组[nums l,nums l+1,…, nums r-1, nums r],并返>回其长度。如果不存在符合条件的子数组,返回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
🥑上文提到:“滑动窗口算法也是一种思想,是双指针的拓展和延伸”。为了更加直观的体现这种思想,我决定用队列来模拟滑动窗口,以队头和队尾作为双指针来进行演示整个题解过程。
🍑我们把数组中的元素不停的入队,直到总和大于等于target为止,接着记录下队列中元素的个数,然后再不停的出队,直到队列中元素的和小于target为止(如果不小于target,也要记录下队列中元素的个数,这个个数其实就是不小于target 的连续子数组长度,我们要记录最小的即可)。接着再把数组中的元素添加到队列中......重复上面的操作,直到数组中的元素全部使用完为止。
这里以[2,3,1,2,4,3]举例画个图来看下:
🥕解题代码
🍏双指针:
public class Main { public static int minSubArrayLen(int target, int[] nums) { int low = 0, high = 0;//low:队头 , high:队尾 int sum = 0, min = Integer.MAX_VALUE; while (high < nums.length) { sum += nums[high++]; while (sum >= target) { min = Math.min(min, high - low); sum -= nums[low++]; } } return min == Integer.MAX_VALUE ? 0 : min; } public static void main(String[] args) { System.out.println(minSubArrayLen(7, new int[]{2, 3, 1, 2, 4, 3})); } }
🍏队列:
public class Main { public static int minSubArrayLen(int target, int[] nums) { int num = 0;//计算子数组的累计和 int min = nums.length;//长度赋初值 boolean flag = false;//判断长度值是否改变过 Deque<Integer> deque = new ArrayDeque<>();//定义出能体现滑动窗口数据结构的数据结构————队列,这样的双端队列更加高效。 int index;//用于记录位置的指针 for (index = 0; index < nums.length; index++) {//设置滑动窗口的初始长度 if (num >= target) { min = Math.min(min, deque.size());//保留之前值与当前值中的较小值 flag = true; break; } deque.addLast(nums[index]);//向队列中添加数据nums[index] num += nums[index]; } //上面的循环用于初始化滑动窗口的长度,此时我们就已经有了一个长度为deque.size()的窗口了 while (num >= target || index < nums.length) { /*此时deque中存放值的总和已经超过了目标值target,此时我们的窗口已经满足的滑动的条件, 如果现在num的值超过目标值就将前面先进入队列deque的值踢出,就相当于窗口就向后移动了一步 */ if (num >= target) { min = Math.min(min, deque.size()); flag = true; num -= deque.poll(); } else {//如果此时不满足num>=target条件就继续向后延伸,向队列deque中推入之后的值加到num中。 num += nums[index]; deque.addLast(nums[index++]); } } if (!flag) return 0; return min; } public static void main(String[] args) { System.out.println(minSubArrayLen(7, new int[]{2, 3, 1, 2, 4, 3})); } }
🐳结语
🐬初学一门技术时,总有些许的疑惑,别怕,它们是我们学习路上的点点繁星,帮助我们不断成长。
🐟文章粗浅,希望对大家有帮助!