滑动窗口-Java【算法学习day.2】

3 篇文章 0 订阅
3 篇文章 0 订阅

一.什么是滑动窗口

滑动窗口是一种双指针算法,基本思路为维护一个窗口,然后从前往后遍历元素进行运算。

//我做这类文档一个重要的目的还是给正在学习的大家提供方向(例如想要掌握基础用法,该刷哪些题?)我的解析也不会做的非常详细,只会提供思路和一些关键点,力扣上的大佬们的题解质量是非常非常高滴!!

共勉!!!


二.在题目中掌握思想(代码中会有注释)

ps:题目均选自力扣

1.长度最小的子数组

题目链接:209. 长度最小的子数组 - 力扣(LeetCode)

题面:

基本分析:子数组是指数组内的索引在父数组中是连续的。

思路:我们可以先定义两个指针,为l,r,分别表示子数组在父数组的范围,我们可以先固定左指针l,然后移动右指针r,左闭右闭,直到找到第一个满足条件的子数组,记录下此时的范围,也就是count=r-l+1,题目既然是让我们找满足条件的长度最小的子数组的长度,那么,正确答案就小于等于count,此时l和r两个指针所围的范围可以看成一个窗口,我们可以从左向右滑动这个窗口,在滑动中判断更新答案,代码和注释如下:

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int n = nums.length - 1;// 采取左闭右闭,所以n=nums.length-1
        int l = 0;// 左指针
        int r = 0;// 右指针
        int sum = 0;// 记录窗口内的总值
        int count = Integer.MAX_VALUE;// 记录窗口的元素个数
        while (r <= n) {
            sum += nums[r++];// 右指针向右滑动,更新窗口内的总值
            // 进入这个循环就表示至少找到了1个解,当找到了一个解,我们就可以开始滑了
            while (sum >= target) {
                // 将当前窗口和过去窗口做比较,能进入这个循环就表示r-l(r-l+1,但r在上面已经++了)是一个解,更新解的最小值
                count = Math.min(count, r - l);
                // 下面这一步很多人最开始会有疑惑,我的理解是:在第一层循环中,右指针是稳定右移的,当我们进入了这个循环,就表示找到了一个解,那么最差的情况,就是第一个找到的解,但是解是小于等于第一个解的,所以我们进入循环就把左边的删1,整体来看就像一个动态变化的窗口在右移
                sum -= nums[l++];
            }
        }
        // 如果count==Integer.MAX_VALUE,表示第二层循环没进,也就是无解
        return count == Integer.MAX_VALUE ? 0 : count;
    }
}

2.最小覆盖子串

题目链接:76. 最小覆盖子串 - 力扣(LeetCode)

题面:

基本分析:虽然是一道困难题,但其实只不过是一道稍微复杂点的滑动窗口,与第一题不同的在于第二层循环的判断条件,在第一题中,根据题意是找sum大于等于target的子数组,进入第二层的判断条件是sum>=target,而这题的判断条件是涵盖t中所有的字符:

什么是涵盖t中的所有字符?:就是对于t中每个字符的数量,某个字符串中的字符数量都大于或等于

分析完后,代码如下

class Solution {
    public String minWindow(String s, String t) {
        int n = s.length() - 1;
        int m = t.length() - 1;
        //如果n<m,不可能涵盖
        if (n < m)
            return "";
        char[] sarr = s.toCharArray();
        char[] tarr = t.toCharArray();
        int[] arr1 = new int[128];//用来记录字符串s中滑动窗口中的字符数量
        int[] arr2 = new int[128];//用来记录字符串t中各字符数量
        //记录字符串t中各字符数量
        for (int i = 0; i <= m; i++) {
            arr2[tarr[i]]++;
        }
        int ni = Integer.MAX_VALUE;//记录子串的左边界
        int nj = Integer.MAX_VALUE;//记录子串的右边界
        int i = 0;//左指针
        int j = 0;//右指针
        int count = Integer.MAX_VALUE;//记录有效子串的长度
        while (j <= n) {
            arr1[sarr[j]]+=1;
            while (isHaveAll(arr1, arr2)) {
                if (j - i + 1 < count) {
                    ni = i;
                    nj = j;
                    count = j - i + 1;
                }
                arr1[sarr[i++]]-=1;
            }

            j++;
        }
        //ni==Integer.MAX_VALUE,表示第二层循环没进,无解
        if (ni == Integer.MAX_VALUE)
            return "";
        return s.substring(ni, nj + 1);
    }

    //此方法用来判断是否满足条件:子串涵盖字符串t
    public boolean isHaveAll(int[] arr1, int[] arr2) {
         for (int i = 'A'; i <= 'Z'; i++) {
            if (arr1[i] < arr2[i]) {
                return false;
            }
        }
        for (int i = 'a'; i <= 'z'; i++) {
            if (arr1[i] < arr2[i]) {
                return false;
            }
        }
        return true;

    }
}

三.后言

上面是滑动串口一些最经典的题目,以后碰到其他好题也会更新,希望有所帮助,一同进步,共勉!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值