zl程序教程

您现在的位置是:首页 >  其他

当前栏目

滑动窗口算法

2023-04-18 13:14:54 时间

                                                                                 🍏🍐🍊🍑🍒🍓🫐🥑🍋🍉🥝

                                                                             啥是滑动窗口,它能解决什么样的问题?



🍐滑动窗口的概念

🍐滑动窗口算法也是一种思想,是双指针的拓展和延伸

    🍊 滑动:说明这个窗口是移动的,也就是移动是按照一定方向来的。
    🍊 窗口:窗口大小并不是固定的,可以不断扩容直到满足一定的条件;也可以不断缩小,直到找到一个满足条件的最小窗口;当然也可以是固定大小。

🍏适用场景

🍏 滑动窗口主要应用在数组和字符串上 ,在一个特定大小的字符串或数组上进行操作,而不在整个字符串和数组上操作,这样就降低了问题的复杂度,从而也达到降低了循环的嵌套深度。

🍋 什么情况适合用滑动窗口来解决实际问题呢?

    🍒 一般给出的数据结构是数组或者字符串
    🍒 求取某个子串或者子序列最长最短等最值问题或者求某个目标值时。

🥑题目示例

题目:长度最小的子数组

题目描述:

给定一个含有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}));
    }

}


🐳结语

🐬初学一门技术时,总有些许的疑惑,别怕,它们是我们学习路上的点点繁星,帮助我们不断成长。

🐟文章粗浅,希望对大家有帮助!

🦄参考文章滑动窗口算法滑动窗口2:滑动窗口算法基本原理滑动窗口详解长度最小的子数组