滑动窗口法
所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
以经典题为例:(力扣链接🔗)

暴力解法:
使用两次for循环即可,然后不断的寻找符合条件的子序列,时间复杂度很明显是#card=math&code=O%28n%5E2%29&id=Lg2lP)。
class Solution {public:int minSubArrayLen(int s, vector<int>& nums) {int result = INT32_MAX; // 最终的结果int sum = 0; // 子序列的数值之和int subLength = 0; // 子序列的长度for (int i = 0; i < nums.size(); i++) { // 设置子序列起点为isum = 0;for (int j = i; j < nums.size(); j++) { // 设置子序列终止位置为jsum += nums[j];if (sum >= s) { // 一旦发现子序列和超过了s,更新resultsubLength = j - i + 1; // 取子序列的长度result = result < subLength ? result : subLength;break; // 因为我们是找符合条件最短的子序列,所以一旦符合条件就break}}}// 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列return result == INT32_MAX ? 0 : result;}};
滑动窗口法:
滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将#card=math&code=O%28n%5E2%29&id=dAC46)的暴力解法降为
#card=math&code=O%28n%29&id=bXs6s)。

class Solution {public int minSubArrayLen(int target, int[] nums) {int left = 0, right = 0, sum = 0, result = Integer.MAX_VALUE;for (; right < nums.length; right++) {sum += nums[right];// 如果大于则进行移动滑动窗口while (sum >= target) {// 取最小序列的长度result = Math.min(result, right - left + 1);// 移动滑动窗口sum -= nums[left++];}}return result == Integer.MAX_VALUE ? 0 : result;}}
相关题目
水果成篮
题目描述(力扣链接)

解题方法
使用哈希表来判断是否重复,使用滑动窗口来更新范围。
class Solution {public int totalFruit(int[] fruits) {// 使用hashMap判断是否重复HashMap<Integer, Integer> map = new HashMap<>();int right = 0, left = 0, result = 0;for (; right < fruits.length; right++) {// 将遍历的元素放入map中map.put(fruits[right], map.getOrDefault(fruits[right], 0) + 1);// 如果其中map的长度超过三,则滑动窗口while (map.size() > 2) {// 将left的取值减一map.put(fruits[left], map.get(fruits[left]) - 1);// 如果left的数量为0之后,则直接清除if (map.get(fruits[left]) == 0) map.remove(fruits[left]);left++;}// 获取其中取得最大的范围result = Math.max(result, right - left + 1);}return result;}}
最小覆盖子串
题目描述(力扣链接)

解题方法:
使用2个哈希表分别记录2个字符串中得词频情况进行判断,使用left和right两个指针在左闭右开的区间进行滑动,当包含t中所有的字符时停止滑动,进行判断,更新结果,再继续进行滑动。
class Solution {public String minWindow(String s, String t) {// 记录窗口中的词频数量HashMap<Character, Integer> window = new HashMap<>();// 记录t中的所有字符,用来查询是否存在HashMap<Character, Integer> map = new HashMap<>();// count为s中包含t字符的个数,result为最小字符串的大小, start记录最小字符串开始的位置int left = 0, right = 0, count = 0, result = Integer.MAX_VALUE, start = 0;// 将t中的字符串全部放入map中for (int i = 0; i < t.length(); i++) {map.put(t.charAt(i), map.getOrDefault(t.charAt(i), 0) + 1);}// 循环进行判断while (right < s.length()) {// 如果map中含有该字符,将字符的value值加一,并且将count加一if (map.containsKey(s.charAt(right))) {window.put(s.charAt(right), window.getOrDefault(s.charAt(right), 0) + 1);if (map.get(s.charAt(right)).equals(window.get(s.charAt(right)))) {count++;}}// 移动窗口右侧进行遍历right++;// 当计数器等于t的大小时,此时窗口需要移动while (count == map.size()) {// 如果窗口大小小于上一个窗口的大小,进行赋值if (right - left < result) {result = right - left;start = left;}// 移动窗口if (map.containsKey(s.charAt(left))) {// 如果window中的值和map中的值数量相等才是包含t的字串if (window.get(s.charAt(left)).equals(map.get(s.charAt(left)))) {count--;}// 将窗口中保存值的数量减一window.put(s.charAt(left), window.getOrDefault(s.charAt(left), 0) - 1);}left++;}}return result == Integer.MAX_VALUE ? "" : s.substring(start, start + result);}}
固定长度的滑动窗口
找到字符串中所有字母异位词
详细见此链接题三
https://www.yuque.com/jugelizi-rxt6d/dqbihl/nm3gl3
