滑动窗口算法详解__java版(与C++的区别注意)

滑动窗口算法详解

一. 算法框架

滑动窗口算法:

int left =0,right =0;
while(right<s.size()){
   
	//增大窗口
	window.add(s[right]);
	right++;
	while(window needs shrink){
   
		//缩小窗口
		window.remove(s[left]);
		left++;
	}
}

其实对应的算法思路很简单,主要是细节比较繁琐。 比如如何向窗口添加新元素,如何缩小窗口,在窗口滑动的哪个阶段更新结果。

滑动窗口套路框架:

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

二.最小覆盖子串

在这里插入图片描述
滑动窗口算法的思路实际上是这样的:

  1. 使用双指针中的左右指针技巧,初始化left=right=0,把[left,right)称为一个窗口。
  2. 先不断增大right,扩大这个窗口,直到窗口满足我们所需的条件(这道题中即,包含了T所有字符)
  3. 再不断增大left,缩小这个窗口,使得我们在保证这个窗口满足条件的同时,尽可能的小。直到窗口内的内容不满足条件,跳出(即不包含T中所有字符了)。每次更新left的时候,也要对最终的结果进行一次更新。
  4. 重复第2和3步,直到right达到了字符串s的尾部。

实际上,增大right是在找可行解,找到可行解后,通过增大left来找最优解(即优化)。

在框架中使用了needs和window字典,他们充当的是计数器的功能。needs用来记录T中每个字符出现的次数,即:我们所需要的字符的情况;window字典则是用来记录当前实际窗口中包含对应字符的情况,通过两个map的对比,来判断是否满足了条件。

回到这道题:
首先,我们初始化needs和window两个哈希表,记录需要凑齐的字符和当前窗口中的字符情况。

String minstr(String s,String t){
   
	Map<Char,Integer> needs = new HashMap<>();
	Map<Char,Integer> window = new HashMap<>();
	for(Char c:t) needs.put(c,map.getOrDefault(c,0)+1);
	

然后,使用left和right变量初始化窗口两端,区间为左闭右开,这样保证了一开始窗口中没有任何元素。

	int left=0,right=0;
	int valid =0;
	while (right<s.size()){
   
		//开始滑动
	}

其中,valid变量表示已经满足条件的字符的个数,如果valid和need中key的数量相等(needs.size()),则说明窗口已满足条件,完全覆盖了T。

接下来需要考虑的问题是:

  1. 扩大窗口时,应该更新哪些数据?
  2. 什么条件下,窗口应暂停扩大,开始移动left? vaild = needs.size()
  3. 缩小窗口时,即移出字符时,应更新哪些数据?
  4. 需要的结果,应该在什么时候更新?应该在缩小窗口时。

完整代码,但是存在很多细节的小问题,后面会一一解答:

String minstr(String s,String t
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值