【力扣刷题笔记】滑动窗口模板

双指针滑动窗口模板

1.使用场景:连续子串/子数组,求和,求序列长度

2.代码模板:

int left = 0;
int right = 0; //双指针,左右边界,表示区间[left, right]
int len = nums.length; //数组长度,字符串长度
int sum = 0; //统计子区间是否有效,可能是求和或者计数
int res = 0; //保存最大满足题目要求的 子数组/子串 长度
while(right < len) {
	sum = sum + nums[right]; //增加右边界的值
	while(区间[left, right] 不符合题目要求) {
		sum = sum - nums[left];
		left++; //移动左指针
	}
	sum = Math.max(res, right - left + 1); //更新结果
	right++; //移动右指针
}

3.模板的思想:

滑动窗口用到了双指针,移动思路:
左指针不动,右指针向后遍历;
当不满足条件,右指针不动,剔除左指针的值,并向后移动左指针,直到满足条件。所以这里用while循环比较好。
然后对左右的边界更新的情况,进行结果的更新。
接着又开始移动右指针,right++,如果是用for循环,那个i就是右指针,i++就是移动右指针。


4.例题

  1. 水果成篮
    76.最小覆盖子串
  2. 字符串的排列

76. 最小覆盖子串

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
注意:

  • 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
  • 如果 s 中存在这样的子串,我们保证它是唯一的答案。

输入:s = “ADOBECODEBANC”, t = “ABC”
输出:“BANC”

粗线条思路:

问题要求我们返回字符串s中包含字符串t的全部字符的最小窗口。
属于找连续子串的覆盖,所以滑动窗口是完美适合;
所以,我们在s上滑动窗口,移动r指针不断扩张窗口,当窗口包含t全部字符,那么收缩窗口,更新得到最小的窗口。

具体分析:所以关键是如何判断窗口包含t中的所需的字符?

即比较窗口的字符,和t中的字符。
想到用两个哈希表,一个哈希表记录t中的所有字符及它们的个数;一个哈希表动态维护滑动窗口中所有的字符及它们的个数。
那么满足要求的条件就是:如果滑动窗口的哈希表,包含t的哈希表中的所有字符,并且对应的个数不小于t的哈希表的各个字符的个数,说明满足条件,记录当前窗口大小。
注意:这里 t 中可能出现重复的字符,所以我们要记录字符的个数。

//两个哈希表,记录字符和个数

Map<Character, Integer> ori = new HashMap<>();
Map<Character, Integer> ori = new HashMap<>();

public String minWindow(String s, String t) {
	int tLen = t.length();
	//获得t中的hash表,记录字符和个数
	for(int i = 0; i < tLen; i++) {
		char c = t.charAt(i);
		ori.put(c, ori.getOrDefault(c, 0) + 1);
	}
	int l = 0, r = -1;//这里右边界是-1,所以循环的时候先r++
	int len =Integer.MAX_VALUE, ansL = -1, ansR = -1;
	int sLen = s.length();
	while(r < sLen) { //遍历右边界指针
		r++;
		if(r < sLen && ori.containsKey(s,charAt(i))) {
			cnt.put(s.charAt(i), cnt.getOrDefault(s.charAt(i), 0) + 1);
		}//如果当前的s字符是t中的字符,放入哈希表中,记录个数
		
		while(check() && l <= r) {
			if(r - l + 1 < len) {
				len = r - l + 1;
				ansL = l;
				ansR = l + len;//记录最小串得左右边界
			}
			if(ori.containsKey(s.charAt(l))) {
				cnt.put(s.charAt(l), cnt.getOrDefault(s.charAt(l), 0) - 1 );
			}	//缩小窗口,移动左指针l,更新窗口的内容,即哈希表的内容
			++l;
		}
	}
	return ansL == -1 ? "" : s.substring(ansL, ansR);
}
//遍历哈希表,键值对转成entry,
public boolean check() {
	Iterator iter = ori.entrySet().iterator();//哈希的迭代器
	while(iter.hasNext()) {
		Map.Entry entry = (Map.Entry) iter.next();// 键值对转成entry
		Character key = (Character) entry.getKey();
		Integer val = (Integer) entry.getValue();
		if(cnt.getOrDeault(key, 0) < val ) {//对应的字符的个数 小于说明不满足
			return false;
		} 
	}
	return true;
}
1. 二分法 5 1.1. 什么是二分查找 5 1.2. 如何识别二分法 5 1.3. 二分法模板 6 1.3.1. 模板一 6 1.3.1.1. 模板代码 6 1.3.1.2. 关键属性 7 1.3.1.3. 语法说明 7 1.3.1.4. Lc69:x的平方根 8 1.3.1.5. Lc374:猜数大小 9 1.3.1.6. Lc33:搜索旋转数组 11 1.3.2. 模板二 13 1.3.2.1. 模板代码 13 1.3.2.2. 关键属性 14 1.3.2.3. 语法说明 14 1.3.2.4. Lc278:第一个错误版本 14 1.3.2.5. Lc162:寻找峰值 16 1.3.2.6. Lc153:寻找旋转排序数组最小值 19 1.3.2.7. Lc154:寻找旋转排序数组最小值II 20 1.3.3. 模板三 22 1.3.3.1. 模板代码 22 1.3.3.2. 关键属性 23 1.3.3.3. 语法说明 23 1.3.3.4. LC-34:在排序数组中查找元素的第一个和最后一个 23 1.3.3.5. LC-658:找到K个最接近的元素 25 1.3.4. 小结 28 1.4. LeetCode中二分查找题目 29 2. 双指针 30 2.1. 快慢指针 31 2.1.1. 什么是快慢指针 31 2.1.2. 快慢指针模板 31 2.1.3. 快慢指针相关题目 32 2.1.3.1. LC-141:链表是否有环 32 2.1.3.2. LC-142:环形链表入口 34 2.1.3.3. LC-876:链表的中间节点 37 2.1.3.4. LC-287:寻找重复数 40 2.2. 滑动窗口 43 2.2.1. 什么是滑动窗口 43 2.1.4. 常见题型 44 2.1.5. 注意事项 45 2.1.6. 滑动窗口模板 45 2.1.7. 滑动窗口相关题目 46 2.1.7.1. LC-3:无重复字符的最长子串 47 2.1.7.2. LC-76:最小覆盖子串 49 2.1.7.3. LC-209:长度最小的子数组 54 2.1.7.4. LC-239:滑动窗口最大值 57 2.1.7.5. LC-395:至少有K个重复字符的最长子串 60 2.1.7.6. LC-567:字符串排列 62 2.1.7.7. LC-904:水果成篮 64 2.1.7.8. LC-424:替换后的最长重复字符 66 2.1.7.9. LC-713:乘积小于K的子数组 67 2.1.7.10. LC-992:K个不同整数的子数组 70 2.3. 左右指针 73 2.3.1. 模板 73 2.3.2. 相关题目 73 2.3.2.1. LC-76:删除倒数第N个节点 74 2.3.2.2. LC-61:旋转链表 76 2.3.2.3. LC-80:删除有序数组中的重复项 79 2.3.2.4. LC-86:分割链表 80 2.3.2.5. LC-438:找到字符串中所有字母的异位词 82 3. 模板 85 2.3.2.6. LC-76:删除倒数第N个节点 85
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值