【刷题笔记】滑动窗口

1.  什么是滑动窗口算法?

滑动窗口算法使用两个指针(通常称为左指针和右指针)来表示当前窗口的边界。在遍历过程中,根据问题的要求和窗口内的状态调整窗口的大小和位置。算法的基本思想是:通过移动窗口的左右边界来维护一个满足特定条件的子区间,并在每次窗口滑动时更新结果。

2. 滑动窗口算法相关题目解题步骤?

滑动窗口算法题型一般是有套路的,具体如下:

  • 初始化窗口:设置左指针和右指针的初始位置,以及一个变量来跟踪满足条件的子序列。
  • 移动右指针:增加右指针,扩大窗口,直到满足题目要求。
  • 判断并更新结果:在满足题目要求的情况下,更新结果变量。
  • 移动左指针:收缩窗口,即移动左指针,直到窗口内不再满足题目要求。
  • 重复步骤2-4:直到右指针遍历完整个序列。

 3. 相关题目

209. 长度最小的子数组

方法一:

这道题我首先用暴力去做,就是双层for循环,第一层循环从数组的每个位置开始,然后第二层循环就从它的后面开始加,直到加到大于等于target为止。这样做就是纯暴力,结果肯定没问题,但是必然超时,所以不推荐。

public int minSubArrayLen(int target, int[] nums) {
        if(nums.length == 1 && nums[0] < target) {
            return 0;
        }
        if(nums.length == 1 && nums[0] >= target) {
            return 1;
        }
        int sum = 0;
        int res = Integer.MAX_VALUE;
        for(int i = 0; i < nums.length; i++) {
            sum = nums[i];
            if(sum >= target) {
                return 1;
            }
            for(int j = i + 1; j < nums.length; j++) {
                sum += nums[j];
                if(sum >= target) {
                    res = Math.min(res, j - i + 1);
                    break;
                }
            }
            sum = 0;
        }
        return res == Integer.MAX_VALUE ? 0 : res;
    }

 方法二:前缀和+二分查找。

如果看过我前面文章的小伙伴,一看到这道题的题干就应该想到用前缀和了,有关子数组的问题一般都可以用前缀和来求解。具体解法,请移步【刷题笔记】前缀和_什么是前缀和-CSDN博客

  方法二:滑动窗口

这道题最好的解法应该是滑动窗口,其实就是定义两个指针,左指针先指向第一个值,让右指针去遍历数组,当求得得和大于等于target得时候,就可以记录这时候子数组得长度了,但是要注意一种情况:

例:假设给定数组如下,目标值为7。

 可见我们先循环找到了{1,2,3,4}符合条件,但是这样就可以返回子数组长度是3了吗?

显然不是!因为我们可以发现{2,3,4}和{3,4}也是满足条件的,因此未来获取最短的子数组,我们还得让left向右移动,然后找到{2,3,4},更新最小子数组长度;再往右移动,找到{3,4},继续更新最小子数组长度;在移动,发现不满足条件了,好left不动了,继续让right去找满足条件的组合,如此循环。

代码详解:

    public int minSubArrayLen(int target, int[] nums) {
        int left = 0;
        int res = Integer.MAX_VALUE;
        int sum = 0;
        for (int right = 0; right < nums.length; right++) {
            sum += nums[right];
            while (sum >= target) {
                res = Math.min(res, right - left + 1);
                sum -= nums[left];
                left++;
            }
        }
        return res == Integer.MAX_VALUE ? 0 : res;
    }

904. 水果成篮

 这道题我是采用hashmap+滑动窗口的方式进行求解的。首先,就是我们让右指针去遍历数组,直到找到水果的种类超过2个,这个时候在让left去移动,直到让map中的水果种类小于等于2种。这里说一下,为什么map可以,而set不行:

例:

 当我们遍历到这个位置的时候,我们找到了{1,4,1},可见如果想继续往下走,需要把“1”和“4”去掉,但是第二个“1”得保留,因为要和后面的数字组成{1,2,2,2},但是如果你用set的话,我们主要是想在set中把“4”给他移除掉,让set里面只剩两个元素,在left走过“4”之前,要先走过1个“1”,但是我们不能确定要走几个“1”才能让“4”的个数为0。然而,如果使用map的话,我们可以把让key为fruits[i],而value则为fruits[i]的个数,这样的话我们就可以随时记录,当“4”的value为0时,left就可以停了。

代码详解:

    public int totalFruit(int[] fruits) {
        int left = 0;
        Map<Integer, Integer> map = new HashMap<>();
        int res = 0;
        for (int right = 0; right < fruits.length; right++) {
            map.put(fruits[right], map.getOrDefault(fruits[right], 0) + 1);
            while (map.size() > 2) {
                map.put(fruits[left], map.get(fruits[left]) - 1);
                if (map.get(fruits[left]) == 0) {
                    map.remove(fruits[left]);
                }
                left++;
            }
            res = Math.max(right - left + 1, res);
        }
        return res;
    }
  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值