滑动窗口算法技巧

news2024/9/25 9:28:05

大家好,我是 方圆。在我刷了一些滑动窗口相关的题目之后,发现很有技巧性,只要掌握了解题思路,就会很简单,所以我决定用这篇帖子记录一下,也帮助同样在刷滑动窗口相关题目的同学。

使用滑动窗口解决的问题一般会有 连续子数组子串 关键信息,我将滑动窗口题目分成两大类:固定窗口动态窗口 问题。前者比较简单,循环维护满足规定大小的窗口即可;后者还能进行细分,分为最大窗口问题和最小窗口问题。最大窗口需要在满足条件的情况下尽可能地扩大 right 指针的值,让窗口尽可能大,最小窗口则是在满足条件的基础上,不断地缩小窗口,让窗口尽可能的小。以上我认为就能将所有滑动窗口问题全部涵盖在内了,大家可以根据自己感兴趣的部分选择性阅读,读完之后推荐做一下相关题目来加深对滑动窗口的理解。如果大家想要找刷题路线的话,可以参考 Github: LeetCode。

固定窗口

在滑动窗口类型的题目中,固定窗口大小的问题是最简单的,我认为它遵循着下面这种模式:

int left = 0, right = 0;
while (right < nums.length) {
    // 相关变量赋值操作

    // 如果在符合窗口大小的情况下进行题解判断
    if (right - left + 1 == windowLength) {
        // 判断是否符合题解,符合条件则记录答案

        // 窗口缩小,将 left 指针处的元素移除
        left++;
    } 

    // 窗口右移
    right++;
}

窗口移动过程中不断扩大,直到满足窗口大小,进行相关逻辑处理,处理完之后把窗口 left 指针处元素移除,缩小窗口,下次再进入循环时,将再次满足指定窗口大小。

下面是一些相关的练习,大家可以做一下,掌握思路之后比较简单:


相关练习
  • 438. 找到字符串中所有字母异位词
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> res = new ArrayList<>();
        int[] mark = new int[26];
        for (char c : p.toCharArray()) {
            mark[c - 'a']++;
        }
        int needCount = p.length();

        int left = 0, right = 0;
        while (right < s.length()) {
            int index = s.charAt(right) - 'a';
            if (mark[index] > 0) {
                needCount--;
            }
            mark[index]--;

            if (right - left + 1 == p.length()) {
                if (needCount == 0) {
                    res.add(left);
                }
                int leftIndex = s.charAt(left) - 'a';
                if (mark[leftIndex] >= 0) {
                    needCount++;
                }
                mark[leftIndex]++;
                left++;
            }

            right++;
        }

        return res;
    }
  • 567. 字符串的排列
    public boolean checkInclusion(String s1, String s2) {
        int[] mark = new int[26];
        char[] s1CharArray = s1.toCharArray();
        for (char c : s1CharArray) {
            mark[c - 'a']++;
        }
        int needCount = s1.length();

        int left = 0, right = 0;
        while (right < s2.length()) {
            int rightIndex = s2.charAt(right) - 'a';
            if (mark[rightIndex] > 0) {
                needCount--;
            }
            mark[rightIndex]--;

            if (right - left + 1 == s1.length()) {
                if (needCount == 0) {
                    return true;
                }
                int leftIndex = s2.charAt(left) - 'a';
                if (mark[leftIndex] >= 0) {
                    needCount++;
                }
                mark[leftIndex]++;
                left++;
            }

            right++;
        }

        return false;
    }
  • 1052. 爱生气的书店老板

这道题的技巧很有意思,我们一起看一下。根据题意可知,老板在不生气的时候,顾客是不变的,而且不生气的状态也不会变成生气,所以我们可以先把能确定的顾客累加计算起来,并把这些累加过的顾客置为零。之后我们维护一个大小为 minutes 的窗口滑动,统计在该固定窗口下能留下的顾客的最大值就是我们能够最多留下的顾客了,最后不生气下的顾客和生气时能留下的最多的顾客即为所求:

    public int maxSatisfied(int[] customers, int[] grumpy, int minutes) {
        int already = 0;
        for (int i = 0; i < customers.length; i++) {
            if (grumpy[i] == 0) {
                already += customers[i];
                customers[i] = 0;
            }
        }
        
        int max = 0;
        int sum = 0;
        int left = 0, right = 0;
        while (right < customers.length) {
            sum += customers[right];
            
            if (right - left + 1 == minutes) {
                max = Math.max(max, sum);
                sum -= customers[left++];
            }
            
            right++;
        }
        
        return already + max;
    }

动态窗口

我认为动态窗口问题可以归为两类,分别是求 最小窗口 和求 最大窗口 问题,我们先来看下解题思路的模板,注意其中的注释信息:

  • 求最小窗口的模板如下:
int left = 0, right = 0;
while(right < nums.length) {
    // 当前元素进入窗口,计算窗口相关值的变化
    doSomething();

    // 求最小窗口:在满足条件的情况下,不断地缩小窗口,即 left 右移
    while(condition && left <[=] right) {
        // 窗口缩小一次记录一次结果值
        res = ?;

        // 移除窗口左边界的值
        left++;
    }

    right++;
}
  • 求最大窗口的模板如下:
int left = 0, right = 0;
while(right < nums.length) {
    // 当前元素进入窗口,计算窗口相关值的变化
    doSomething();

    // 求最大窗口:在不满足条件的情况下,不断地缩小窗口来试图满足条件,即 left 右移
    while(condition && left <[=] right) {
        // 不断地移除窗口左边界的值,直到符合条件
        left++;
    }
    // 计算结果值
    res = ?;

    right++;
}

我们可以发现这两个模板很像,不同的是 while 循环条件和计算结果值的位置:

  • 计算最小窗口是在 满足条件的情况下不断的缩小窗口,每移动一次都需要计算一次结果,因为每次移动都比当前的窗口小;

  • 计算最大窗口时,我们需要让 right 指针尽可能地右移,右移的越多则窗口越大,只有在不满足条件时才缩小窗口,那么 while 条件需要在 不满足条件的情况下不断地缩小窗口直到条件满足,保证在 while 代码块处理完之后都是符合题意的,再计算结果值就没有问题了。

此外,需要注意 while 循环中被标记的等号条件,如果有的题目条件要求将窗口内所有元素都移除的话,则需要等号,否则不需要。

下面的题目都是结合以上模板思路来的,大家可以练习一下,我相信你会发现动态滑动窗口可以很简单。


相关练习
  • LCR 008. 长度最小的子数组

我们先来看下这道题,由题意可知我们需要在 满足条件时不断地(while) 缩小窗口,以此来得到最小的窗口,注意其中 left <= right 的等号条件,因为可能存在单个值要比 target 大的情况,所以需要添加等号,必要时将窗口内所有元素都移除:

    public int minSubArrayLen(int target, int[] nums) {
        int res = Integer.MAX_VALUE;
        int sum = 0;
        int left = 0, right = 0;
        while (right < nums.length) {
            sum += nums[right];

            while (sum >= target && left <= right) {
                res = Math.min(res, right - left + 1);
                sum -= nums[left++];
            }

            right++;
        }

        return res == Integer.MAX_VALUE ? 0 : res;
    }
  • 76. 最小覆盖子串

别看这道是困难的题目,但是逻辑和上一题基本一致,都是在满足条件的情况下,不断地(while) 缩小窗口以获取最小的窗口:

    public String minWindow(String s, String t) {
        String res = "";
        int[] mark = new int[128];
        for (char c : t.toCharArray()) {
            mark[c]++;
        }
        int needCount = t.length();

        int left = 0, right = 0;
        while (right < s.length()) {
            if (mark[s.charAt(right)] > 0) {
                needCount--;
            }
            mark[s.charAt(right)]--;

            while (needCount == 0 && left <= right) {
                if ("".equals(res) || right - left + 1 < res.length()) {
                    res = s.substring(left, right + 1);
                }
                if (mark[s.charAt(left)] >= 0) {
                    needCount++;
                }
                mark[s.charAt(left++)]++;
            }

            right++;
        }

        return res;
    }
  • 713. 乘积小于 K 的子数组

  • 992. K 个不同整数的子数组

713 题目和 992 题目基本相同,我们以 992 为例,来讲解一下这道题的思路,明白了其中的要点 713 题目也会迎刃而解。

首先我们需要了解:当前区间子数组数量为区间元素个数,如下图所示:

区间子数组.png

我们接着看:992 题目要求统计数组中不同整数为 k 的子数组数目,我们以 nums = [1, 2, 1, 2, 3], k = 2 为例,符合条件的数组为:[1, 2], [1, 2, 1], [1, 2, 1, 2], [2, 1], [2, 1, 2], [1, 2], [2, 3]。在统计 [1, 2] 区间的子数组时,采用上述方法计算子数组数量为 2,我们需要去掉其中不符合条件的子数组 [1],计数值为 1;在统计 [1, 2, 1] 区间时,子数组计数为 3,其中 [1, 2, 1] 和 [2, 1] 符合条件,而 [1] 不符合条件,需要去掉,所以计数值为 2;[1, 2, 1, 2] 区间同理,不再赘述。我们可以发现某个符合条件的区间,采用上述计数算法时会将不符合条件的区间也包含进来,例如区间 [1, 2] 它的子数组为 2,而符合 k = 2 条件的子数组数为 1,我们需要将 k = 1 的区间删掉。解题思路能确定下来了:即把符合条件 k 的区间计数下来,然后将符合条件 k - 1 的区间数量减去。

但是,我们还是拿区间 [1, 2] 看一下,如果我们统计 k = 1 的所有区间,发现它的数量为 2,即 [1] 和 [2],而区间 [1, 2] 的子数组数量也为 2,此时作差得到的结果为 0,而不是 1,这是哪里出了问题呢?我们看一下统计的 k = 1 的所有区间,[2] 是包含在 [1, 2] 的子数组中需要被去掉的没有问题,但是我们统计的 [1] 可没有包含在 [1, 2] 的子数组中,这样我们相当于多去掉了一个数量,导致我们结果不对,所以我想到了两个办法解决:

  1. 将 1 ~ k 所有符合条件的区间数量全部统计出来,再将 1 ~ k - 1 所有符合条件的区间全部统计出来,用前者减去后者即为所求,拿 [1, 2] 为例,统计 k = 1 和 k = 2 的子数组数量为 3,k = 1 的子数组数量为 2,作差即为答案

  2. 当找到符合条件 k 的区间时,统计子数组数量,并将其中子数组符合 1 ~ k - 1 条件的子数组移除,这也能得到我们想要的答案,大家感兴趣可以试一下

题解是根据方法 1 写出来的,如下:

    public int subarraysWithKDistinct(int[] nums, int k) {
        return doSubarraysWithKDistinct(nums, k) - doSubarraysWithKDistinct(nums, k - 1);
    }


    private int doSubarraysWithKDistinct(int[] nums, int k) {
        int res = 0;
        HashMap<Integer, Integer> numCounts = new HashMap<>();
        int left = 0, right = 0;
        while (right < nums.length) {
            numCounts.put(nums[right], numCounts.getOrDefault(nums[right], 0) + 1);

            while (numCounts.size() > k && left <= right) {
                Integer count = numCounts.get(nums[left]);
                if (count == 1) {
                    numCounts.remove(nums[left]);
                } else {
                    numCounts.put(nums[left], --count);
                }
                left++;
            }

            res += right - left + 1;
            right++;
        }

        return res;
    }
  • 3. 无重复字符的最长子串

这道题要找最长子串,看到最长那么我们肯定是需要在符合条件的情况下疯狂地(while)把 right 指针向右滑动,在不符合条件地情况下不断地删除 left 指针处的字符直到符合条件为止,注意其中 left < right 的条件,我们没加等号,因为单个字符是一定不会重复的:

    public int lengthOfLongestSubstring(String s) {
        int res = 0;
        HashSet<Character> mark = new HashSet<>();
        int left = 0, right = 0;
        while (right < s.length()) {
            while (mark.contains(s.charAt(right)) && left < right) {
                mark.remove(s.charAt(left++));
            }
            mark.add(s.charAt(right));
            res = Math.max(res, right - left + 1);

            right++;
        }

        return res;
    }
  • 1695. 删除子数组的最大得分

本题和上一题思路一致,上一题会了这题根本不可能做不出来!!!

    public int maximumUniqueSubarray(int[] nums) {
        HashSet<Integer> mark = new HashSet<>();
        int res = 0;
        int sum = 0;
        int left = 0, right = 0;
        while (right < nums.length) {
            sum += nums[right];
            while (mark.contains(nums[right]) && left < right) {
                sum -= nums[left];
                mark.remove(nums[left++]);
            }
            mark.add(nums[right]);
            res = Math.max(res, sum);

            right++;
        }

        return res;
    }
  • 904. 水果成篮

本题是需要满足的条件是最大的窗口大小不能超过 2,超过 2 时不断地将窗口左侧的水果种类移除即可:

    public int totalFruit(int[] fruits) {
        int res = 0;
        HashMap<Integer, Integer> fruitTypeNum = new HashMap<>();
        int left = 0, right = 0;
        while (right < fruits.length) {
            fruitTypeNum.put(fruits[right], fruitTypeNum.getOrDefault(fruits[right], 0) + 1);

            while (fruitTypeNum.size() > 2 && left < right) {
                Integer num = fruitTypeNum.get(fruits[left]);
                if (num == 1) {
                    fruitTypeNum.remove(fruits[left]);
                } else {
                    fruitTypeNum.put(fruits[left], --num);
                }
                left++;
            }

            res = Math.max(res, right - left + 1);
            right++;
        }

        return res;
    }
  • 1004. 最大连续1的个数 III

刷题刷到这里突然觉得简单起来了!这个也是典型的动态窗口,在不满足条件的情况下,我们需要不断地(while)缩小窗口来满足条件,注意其中的 left <= right,因为 k 可能为 0,必要时需要将窗口内的单个元素 0 在窗口中移除:

    public int longestOnes(int[] nums, int k) {
        int res = 0;
        int left = 0, right = 0;
        while (right < nums.length) {
            if (nums[right] == 0) {
                k--;
            }

            while (k < 0 && left <= right) {
                if (nums[left] == 0) {
                    k++;
                }
                left++;
            }
            res = Math.max(res, right - left + 1);

            right++;
        }

        return res;
    }
  • 1208. 尽可能使字符串相等

本题和上一题基本一致,依然是在不满足条件的情况下不断地(while)缩小窗口,在条件中添加了等于号,因为如果单个元素开销过大也需要被移除:

    public int equalSubstring(String s, String t, int maxCost) {
        int res = 0;
        int left = 0, right = 0;
        while (right < s.length()) {
            maxCost -= Math.abs(s.charAt(right) - t.charAt(right));

            while (maxCost < 0 && left <= right) {
                maxCost += Math.abs(s.charAt(left) - t.charAt(left));
                left++;
            }
            res = Math.max(res, right - left + 1);

            right++;
        }

        return res;
    }
  • 424. 替换后的最长重复字符

这道题虽然和其他求最大窗口题目的思路一致,但是窗口缩小的条件并不是特别容易想出来,我们一起看一下:每次窗口滑动都记录当前窗口内最大的字符数量,如果 当前窗口长度 - 最大字符数量 > 能够替换的字符数 的话,那么我们就需要不断地缩小窗口。

虽然我们记录了当前窗口内的最大字符数量,并没有记录具体哪个字符的数量是最多的,缩小窗口的时候只是简单的将窗口 left 指针左移了而已,那有同学会问了,如果 left 指针处的字符正好是字符数量最大的字符怎么办,这个时候我们缩小它,执行替换的次数应该不变呀?确实,但是有一个问题需要思考一下:字符的顺序需要被考虑进来吗?我们现在已经记录了当前窗口内数量最多的字符数,那么我们每将窗口缩小一次,就相当于将非最大数量的字符移除,当窗口大小和窗口内最多的字符数相等时,就相当于是把所有非最大数量字符全部移除了,也就是没有发生任何字符替换的情况,这样我们每次都是维护当前窗口内的最大字符数,通过缩小窗口大小表示将其他字符移除,来达到满足条件的窗口,这样再计算结果值,大家再想一想,是不是呢:

    public int characterReplacement(String s, int k) {
        int res = 0;
        int maxCount = 0;
        int[] mark = new int[26];
        int left = 0, right = 0;
        while (right < s.length()) {
            int index = s.charAt(right) - 'A';
            mark[index]++;
            maxCount = Math.max(maxCount, mark[index]);

            while (right - left + 1 - maxCount > k) {
                mark[s.charAt(left++) - 'A']--;
            }
            res = Math.max(res, right - left + 1);

            right++;
        }

        return res;
    }
  • 2024. 考试的最大困扰度

与上一题思路一致,不再赘述:

    public int maxConsecutiveAnswers(String answerKey, int k) {
        int res = 0;
        int tCount = 0, fCount = 0;
        int left = 0, right = 0;
        while (right < answerKey.length()) {
            if (answerKey.charAt(right) == 'T') {
                tCount++;
            } else {
                fCount++;
            }
            int maxCount = Math.max(tCount, fCount);

            while (right - left + 1 - maxCount > k) {
                if (answerKey.charAt(left) == 'T') {
                    tCount--;
                } else {
                    fCount--;
                }
                left++;
            }
            res = Math.max(res, right - left + 1);

            right++;
        }

        return res;
    }

巨人的肩膀

  • 【深度解析】这道题和76. 最小覆盖子串的区别

  • c++ 滑动窗口,理解 right - left 【992. K 个不同整数的子数组】

  • [滑动窗口真滴简单!] 闪电五连鞭带你秒杀12道中档题 (附详情解析)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1074491.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PADS规则设置

一&#xff0e;设置类规则(DRC检测规则) 默认所有类规则设置网络属性分类设置 网络属性附着颜色 选择电源类在DDR中设置非常实用 创建组合 方便模块整旋转移动 二,元件组合 选择组合 旋转组合 CtrlR旋转90&#xff1b;双击旋转任意角度 拆开组合(还独立元件操作) 三,设置过孔…

【java学习】多维数组(10)

文章目录 1. 二维数组 1. 二维数组 二维数组[][]&#xff1a;数组中的数组 格式1&#xff08;动态初始化&#xff09;&#xff1a;int[][] arr new int[3][2]; 解释说明&#xff1a; 定义了名称为arr的二维数组二维数组中有3个一维数组每个一维数组中有2个元素一维数组的名称…

教资面试多烂才不合格 教师资格证面试难度分析

教资面试是否合格&#xff0c;主要取决于考生的表现是否符合教师职业要求和教育教学能力。以下是一些可能导致教资面试不合格的表现&#xff1a; 对教育事业缺乏热情&#xff0c;对所教授的学科不感兴趣&#xff0c;或者对教育工作没有正确的认知。 对学生的关注不足&#xf…

C++学习day3

目录 作业&#xff1a; 1> 思维导图 2>设计一个Per类&#xff0c;类中包含私有成员:姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员:成绩、Per类对象p1&#xff0c;设计这两个类的构造函数、析构函数和拷贝构造函数。 效果图…

【ICer的脚本练习】shell的三剑客:grep/sed/awk

系列的目录说明请见:ICer的脚本练习专栏介绍与全流程目录_尼德兰的喵的博客-CSDN博客 前言 大大小小的脚本我们写了几个了,在上一篇我们借助bashrc简单了解了bash语言的一些语法和组织规则。这一篇呢我们还是回到shell简单看下三个常用命令,毕竟脚本也可以视为复杂的命令尤…

c++运算符

文章目录 运算符位运算符类型转换 运算符 #include<iostream> using namespace std;int main() {// 算术运算符cout << "1 2 " << 1 2 << endl; cout << "1 2 - 3 * 4 " << 1 2 - 3 * 4 << endl;short a…

mfoc-hardnested在visual studio2022编译

1、点击mfoc-hardnested.sln 2、没有clang LLVM (clang-cl) (未安装) 打开installer 点击修改: 单个组件中搜索clang &#xff0c;安装即可 3、编译 4、main函数 5、mfoc-hardnested.exe使用

v-on事件处理指令;简写@事件名

一、v-on 给元素&#xff08;标签&#xff09;绑定事件监听器 oninput、onclick、onchange、onblur等 1、 完整方式v-on:事件名“函数/方法” 2、简写方式事件名“函数/方法”&#xff0c;注意符号不能加冒号“&#xff1a;” input /click/change/blur ..... 代码如下&#xf…

为什么不建议使用SELECT * ?

“不要使用SELECT ”几乎已经成为数据库使用的一条金科玉律&#xff0c;就连很多公司也明确表示不得使用作为查询的字段列表&#xff0c;更是让这条规则拥有了权威的加持。 为什么不建议直接使用SELECT *&#xff1f;我们总得搞清楚这其中的原因吧&#xff0c;不要别人说不建议…

vue3 组件v-model绑定props里的值,修改组件的值要触发回调

很早之前就写了&#xff0c;一直没写篇博客记录下 <select v-model"typeVal" />const emit defineEmits([update:type]); const props defineProps({type: { type: String, default: }, });const typeVal computed({get() {return props.type;},set(value…

Flutter:open_file打开本地文件报错问题

相关插件及版本&#xff1a; open_file: ^3.2.1 问题&#xff1a; 项目中一直用的这个插件&#xff0c;突然发现在安卓高版本不能正常使用&#xff0c;报权限问题permissionDenied&#xff0c;断点调试提示相关权限是MANAGE_EXTERNAL_STORAGE&#xff0c;申请权限之后还是不行&…

PDF有限制不能复制怎么办?

大家现在接触PDF文件越来越多&#xff0c;有的时候在网上下载的PDF文件打开之后&#xff0c;发现选中文字之后无法复制。甚至其他功能也都无法使用&#xff0c;这是怎么回事&#xff1f;该怎么办&#xff1f; 当我们发现文件打开之后&#xff0c;编辑功能无法使用&#xff0c;很…

探索视觉系统工作原理,聚焦机器人应用“新视界”

原创 | 文 BFT机器人 01 视觉系统&#xff1a;机器人的“眼睛” 视觉系统是一个非常复杂的系统&#xff0c;包括照明系统、镜头、摄像系统和图像处理系统。机器视觉系统主要由三部分组成&#xff1a;图像的获取、图像的处理和分析、输出或显示。 从功能上看&#xff0c;典型的…

Allegro批量剪断走线操作

在用Allegro设计 PCB过程中,有时候由于原理图改动,导致布局的改动。这就会导致走完的线要重新走,对于差分对因为前半部分的走线是不用重新走的。那就可以使用剪断后面部分的线,然后删除,提高走线的效率。那如何批量剪断走线呢? (1)选择菜单Manufacture→Drafting→Dele…

ROS2学习(六)Bag回放使用plotjugger

Plotjugger Plotjugger是一个类似rqt_plot的可视化工具&#xff0c;但PlotJuggler拥有更强大和好用的功能。你可以导入文本文件让它显示文本文件中的数据&#xff0c;可以导入csv等各种格式的文件&#xff0c;支持画出数据曲线2. Bag回放 使用Plotjugger 可以导入ros的bag包…

docker pull 拉取镜像报错

报错信息&#xff1a;Error response from daemon: toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limit 简单理解就是拉取镜像失败&#xff0c;外部原因&…

HDLbits: Lfsr5

我的错误写法&#xff0c;半成品&#xff0c;完全错误&#xff1a; module top_module(input clk,input reset, // Active-high synchronous reset to 5h1output [4:0] q ); dff dff_1(clk, 0 ^ q[0],q[4]);dff dff_2(clk, q[4] ,q[3]);dff dff_3(clk, q[3] ^ q[0] ,q[2]);…

2023年中国棋牌桌市场规模及行业前景:更具创意和功能是未来趋势[图]

棋牌桌行业是指涉及棋牌类游戏的桌面制造、销售和相关服务的产业&#xff0c;它包括生产和销售各种类型的棋牌桌&#xff0c;如象棋桌、扑克桌、麻将桌等&#xff0c;以及提供与这些游戏相关的配件和设备。 棋牌桌行业分类 资料来源&#xff1a;共研产业咨询&#xff08;共研网…

Android多线程学习:多线程同步

一、多线程 多线程就是指一个进程中同时有多个线程正在执行。 二、多线程优缺点&#xff1a; 优点&#xff1a; 1、提高程序运行效率&#xff0c;如同时上传多个图片&#xff1b; 2、耗时操作放子线程执行&#xff0c;提高主线程执行效率&#xff0c;无需等待。 缺点&#…

【Spring MVC研究】聊聊web绑定器(WebDataBinder、@InitBinder)

文章目录 1. 绑定器的作用2. 使用方式&#xff08;测试代码&#xff09;InitBinder3. 相关的几个核心类的真实类型4. 原理4.1. 正向推理4.2. 反向推理4.3. 正向反向推理结合分析4.4. 重点来了&#xff08;如果前后衔接是接4.3章节&#xff09;4.4.1. InitBinder注解的注册4.4.2…