滑动窗口算法可以用以解决数组/字符串的子元素问题,它可以将嵌套的循环问题,转换为单循环问题,降低时间复杂度。
滑动窗口算法思路很简单:维护一个窗口,不断滑动,然后更新答案。
下面提供一种滑动窗口算法的框架:
public boolean checkInclusion(String s1, String s2) {
//先将s1转换成hashmap
HashMap need = new HashMap<>();
for (int i = 0; i < s1.length(); i++){
char t = s1.charAt(i);
need.put(t, need.getOrDefault(t,0)+1);
}
//准备滑动窗口,hashmap的window,left,right,vaild标志位
HashMap window = new HashMap<>();
int left = 0;
int right = 0;
int vaild = 0;
//开始滑动窗口
while (right < s2.length()){
//c将要移入窗口的字符
char c = s2.charAt(right);
right++;
//进行窗口内数据的更新
if (need.containsKey(c)){
window.put(c,window.getOrDefault(c,0)+1);
if (need.get(c).equals(window.get(c))){ //为什么要判断这个,就是要用标志位来标记数量相等
vaild++;
}
}
//处理左边界移动
while (right - left >= s1.length()){
//当标志位等于need的长度说明两个刚好相同
if (vaild == need.size()){
return true;
}
//t表示将要移出窗口的字符
char t = s2.charAt(left);
left++;
if (need.containsKey(t)){
if (need.get(t).equals(window.get(t))){
vaild--;
}
window.put(t,window.getOrDefault(t,0)-1);
}
}
}
return false;
}
题目
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。 如果 s 中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = "ADOBECODEBANC", t = "ABC" 输出:"BANC" 示例 2:
输入:s = "a", t = "a" 输出:"a" 示例 3:
输入: s = "a", t = "aa" 输出: "" 解释: t 中两个字符 'a' 均应包含在 s 的子串中, 因此没有符合条件的子字符串,返回空字符串。
对于子串的题目,优先想到滑动窗口。
题目中要求s中涵盖t中所有字符的最小子串,那么有几点:
1、s涵盖t中所有字符
2、s是最小子串
那么需要滑动窗口含有t中的所有字符,并且要是最小的。
因此,我们用一个标志valid来判断是否窗口中元素的个数和t中的一致。
代码如下
import java.util.HashMap;
public class leetcode76 {
public String minWindow(String s, String t) {
//用hashmap将t转换成hashmap结构
HashMap need = new HashMap<>();
for (int i = 0; i < t.length(); i++){
char ts = t.charAt(i);
need.put(ts, need.getOrDefault(ts,0)+1);
}
//定义一个hashmap,作为窗口window,左右分别为left,right,长度len,标志位vaild,最后左边起始start
HashMap window = new HashMap<>();
int left = 0;
int right = 0;
int len = Integer.MAX_VALUE;
int vaild = 0;
int start = 0;
//开始滑动窗口
while (right < s.length()){
char c = s.charAt(right);
right++;
if (need.containsKey(c)){
window.put(c, window.getOrDefault(c,0)+1);
if (window.get(c).equals(need.get(c))){
vaild++; //表示窗口中一个元素的个数和t中的一样
}
}
//判断是否需要滑动窗口
while (vaild == need.size()){
if (right - left < len){
start = left;
len = right - left;
}
char l = s.charAt(left);
left++;
if (need.containsKey(l)){
if (window.get(l).equals(need.get(l))){
vaild--;
}
window.put(l, window.getOrDefault(l,0)-1);
}
}
}
if (len == Integer.MAX_VALUE){
return "";
} else {
return s.substring(start,start+len);
}
}
public static void main(String[] args) {
leetcode76 le = new leetcode76();
String s = "ADOBECODEBANC";
String t = "ABC";
System.out.println(le.minWindow(s,t));
}
}