给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串。
示例:
输入: S = “ADOBECODEBANC”, T = “ABC”
输出: “BANC”
说明:
如果 S 中不存这样的子串,则返回空字符串 “”。
如果 S 中存在这样的子串,我们保证它是唯一的答案。
思路:
- 如果使用暴力遍历子串的方法,肯定不是该题的最优解
- 使用动态窗口的方法,left和right两个指针来限定窗口的范围
- 窗口进行变化的规则:right往右走表示窗口的扩展,left往右走表示窗口的收缩。先将窗口进行扩展,如果窗口覆盖了所有子串,这时说明right位置的元素肯定是需要的,但是left由于是最开始的,有可能时不需要的,这时将窗口进行收缩,如果收缩的下标是需要的,则上一时刻窗口已经是一个最小时刻了,收缩后可能不满足条件,然后进行下一次匹配,窗口继续进行扩张。如果收缩的下标是不需要的,那么窗口就会不断缩小,直到缩小到一个最小时刻为止。这样重复该过程,遍历完整个主串,就会在该过程中筛选出所有满足的情况,再筛选出最小的
- 那么如何去判断是否覆盖子串,可以用一个map来记录子串中的元素的需要情况,因为子串中的元素可能出现重复,key为要记录的元素,value是完成覆盖需要的个数
value = 0 ,表示刚好满足,不需要
value > 0 ,表示需要value个
value < 0 ,表示多余value的绝对值个 - 在第四条中已经维护了一个map,去随时更新窗口中的覆盖情况,如何判断是否满足,肯定不可能每次去遍历,这样时间复杂度会很高,所以可以维护一个计数器,用来计数子串中已经覆盖的个数,比如子串“abc”,那么刚开始计数器count=3,当窗口中有a了后,count=2,这样当count=0时,也就能判断完成了覆盖。
- 维护count值的变化并不是说每次都需要更新。当扩张时,有可能窗口中已经满足了覆盖了这个元素,已经不需要了,但是map需要进行维护,count是不用变化的,如果子串需要这个元素,count就要减一。同样,当缩小时,要判断缩小的这个元素我是否多余,如果没有多余,那么count就要加一
public static String minWindow(String s, String t) {
if(s == null || t == null || s.length() <= 0 || t.length() <= 0 || s.length()<t.length()) {
return "";
}
//定义左右两个指针,right=-1的意义在于上去就要先走一步
int left = 0;
int right = -1;
//定义窗口的最小值,窗口的最小字符串
int min = s.length();
String minS = "";
//定义一个map,统计t中的各字符个数
HashMap<Character, Integer> map = new HashMap<>();
for (int i = 0; i < t.length(); i++) {
Integer num = map.get(t.charAt(i));
if(num == null) {
map.put(t.charAt(i),1);
} else {
map.put(t.charAt(i),num+1);
}
}
//记录t中还需要有的字母个数
int count = t.length();
//开始窗口移动
while (true) {
//窗口只能向一个方向移动,判断扩张还是收缩,如果满足情况则收缩,否则扩张
if(count <= 0) {
if(min >= (right-left+1)) {
min = (right-left+1);
minS = s.substring(left,right+1);
}
//收缩过程
left++;
if(left >= s.length()) {
break;
}
char leftCur = s.charAt(left-1);
Integer num = map.get(leftCur);
if(num == null) {
continue;
}
if(num >= 0) {
count++;
}
map.put(leftCur,num+1);
} else {
//扩张过程,向右一步
right++;
if(right >= s.length()) {
break;
}
char rightCur = s.charAt(right);
Integer num = map.get(rightCur);
if(num == null) {
continue;
}
if(num > 0) {
count--;
}
map.put(rightCur,num-1);
}
}
return minS;
}