滑动窗口(SildeWindow)

1 滑动窗口的思想

滑动窗口算法框架
伪代码

		void slidingWindow(String s, String t) {
   
	        HashMap<Character, Integer> need = new HashMap<>();
	        HashMap<Characte,Integer> window = new HashMap<>();
	        for (char c : t.tCharArray()) {
   
	            need.put(c, need.getOrDefault(c, 0) + 1);
	        }
	        int left = 0, right = 0;
	        int valid = 0;
	        while (right < s.length()) {
   	           
	            char c = s.charAt(right);  // c 是将移入窗口的字符           
	            right++;                   // 右移窗口           
	            ...                        // 进行窗口内数据的一系列更新
	    
	            System.out.print("window: [%d, %d)\n", left, right); //debug 输出的位置
	    
	            // 判断左侧窗口是否要收缩
	            while (window needs shrink) {
   
	               
	                char d = s.charAt(left); // d 是将移出窗口的字符               
	                left++;                  // 左移窗口 
	                ...                      // 进行窗口内数据的一系列更新
	            }
	        }
	    }

需要变化的地方

  • 1、右指针右移之后窗口数据更新
  • 2、判断窗口是否要收缩
  • 3、左指针右移之后窗口数据更新
  • 4、根据题意计算结果

在滑动窗口类型的问题中都会有两个指针,一个用于「延伸」现有窗口的 R 指针,和一个用于「收缩」窗口的 L 指针。
在任意时刻,只有一个指针运动,而另一个保持静止。
我们在 s 上滑动窗口,通过移动 r 指针不断扩张窗口。
当窗口包含 t 全部所需的字符后,如果能收缩,我们就收缩窗口直到得到最小窗口。

2 常见题型

2.1 (lee-567) 字符串的排列

给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。

输入: s1 = “ab” s2 = “eidbaooo”
输出: True
解释: s2 包含 s1 的排列之一 (“ba”)

方式 1: 滑动窗口

思路:由于排列不会改变字符串中每个字符的个数,所以只有当两个字符串每个字符的个数均相等时,一个字符串才是另一个字符串的排列。根据这一性质,记 s1​ 的长度为 n,我们可以遍历 s2中的每个长度为 n 的子串,判断子串和 s1​ 中每个字符的个数是否相等,若相等则说明该子串是 s1​ 的一个排列。

	public boolean checkInclusion(String s1, String s2) {
   
        // window 记录窗口中的字符, 记录需要凑齐的字符(need)
        HashMap<Character, Integer> window = new HashMap<>();
        HashMap<Character, Integer> need = new HashMap<>();
        for (char c : s1.toCharArray()) {
   
        	need.put(c, need.getOrDefault(c, 0) + 1);
        }
        int left = 0, right = 0;
        int flag = 0;
        
        while (right < s2.length()) {
   
            char c = s2.charAt(right);
            if (need.containsKey(c)) {
   
                window.put(c, window.getOrDefault(c, 0) + 1);
                if (window.get(c).equals(need.get(c))) {
    
                    flag++;
                }
            }
            while (right - left + 1 == s1.length()) {
   
                if (flag == need.size()) {
   
                	return true;
                }
                char c1 = s2.charAt(left);
                left++;
                if (need.containsKey(c1)) {
   
                    if (window.get(c1).equals(need.get(c1))) {
   
                        flag--;
                    }
                    window.put(c1, window.get(c1) - 1);
                }
            }
            right++;
        }
        return false;
	}

方式 2:优化

	/**
	 * 思路:由于需要遍历的子串长度均为 n,我们可以使用一个固定长度为 n 的滑动窗口来维护 cnt2
	 * 滑动窗口每向右滑动一次,就多统计一次进入窗口的字符,少统计一次离开窗口的字符。
	 * 然后,判断 cnt1 是否与 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值