题目
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串""
。
注意:
- 对于
t
中重复字符,我们寻找的子字符串中该字符数量必须不少于t
中该字符数量。 - 如果
s
中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = “ADOBECODEBANC”, t = “ABC” 输出:“BANC”
解题思路:双指针滑动窗口
本问题要求我们返回字符串 中包含字符串
的全部字符的最小窗口。我们称包含
的全部字母的窗口为「可行」窗口。
我们可以用滑动窗口的思想解决这个问题。在滑动窗口类型的问题中都会有两个指针,一个用于「延伸」现有窗口的 指针,和一个用于「收缩」窗口的
指针。在任意时刻,只有一个指针运动,而另一个保持静止。我们在
上滑动窗口,通过移动
指针不断扩张窗口。当窗口包含
全部所需的字符后,如果能收缩,我们就收缩窗口直到得到最小窗口。
注意:这里 **t**
中可能出现重复的字符,所以我们要记录字符的个数。
考虑如何优化?
如果 ,
,那么显然
是第一个得到的「可行」区间,得到这个可行区间后,我们按照「收缩」窗口的原则更新左边界,得到最小区间。我们其实做了一些无用的操作,就是更新右边界的时候「延伸」进了很多无用的
,更新左边界的时候「收缩」扔掉了这些无用的
,做了这么多无用的操作,只是为了得到短短的
。因此我们需要在最开始的时候对于临时表为空,且不在字串中的字符进行丢弃,将
这情况的无用的
全部丢弃。
复杂度分析
时间复杂度:
- 开始需要对  中的元素都执行一次插入,最坏情况下左右指针对  的每个元素各遍历一遍,每次检查是否可行会遍历整个  的哈希表,哈希表的大小与字符集的大小有关,设字符集大小为  ,则渐进时间复杂度为  。
空间复杂度:
- 这里用了两张哈希表作为辅助空间,每张哈希表最多不会存放超过字符集大小的键值对,我们设字符集大小为  ,则渐进空间复杂度为  。
我的代码
public class Solution {
public boolean CharEnoughInT( HashMap<Character,Integer>submap, HashMap<Character,Integer>tempmap){
// 字符都不满足
if(submap.size()>tempmap.size()) return false;
// entry 是子串必须要具备的
for(Map.Entry<Character,Integer> entry:submap.entrySet()){
// 字串当前字符个数多于临时串说明不匹配
if(entry.getValue()>tempmap.getOrDefault(entry.getKey(),0))
return false;
}
return true;
}
public String minWindow (String S, String T) {
// write code here
HashMap<Character,Integer>submap=new HashMap<>(); // 记录T的哈希表
HashMap<Character,Integer>tempmap=new HashMap<>(); // 记录临时串的哈希表
// 将字串的哈希打表
for(int i=0;i<T.length();i++){
char c=T.charAt(i); // 得到T的当前字符
submap.put(c,submap.getOrDefault(c,0)+1);
}
// 双指针
int l=0,r=0;
int resL=0,resR=Integer.MAX_VALUE;
// 遍历右指针
for(r = 0;r<S.length();r++){
char c=S.charAt(r); // 得到S的当前字符
// 如果临时字符是空的,当前字符还不在字串中那么可以lr直接跳过
if(tempmap.size()==0 && !submap.containsKey(c)){
l=r+1;
continue;
}
// 插入当前字符串,由于不清楚是否存在先查,查到原基础+1,查不到设置1
tempmap.put(c,tempmap.getOrDefault(c,0)+1);
// 此时临时字符串不是空的,判断是否满足条件临时串覆盖了字串
while(CharEnoughInT(submap,tempmap)){
// 满足字串,查看能否刷新长度
if((resR-resL)>(r-l)){
resL=l;
resR=r;
}
// l指针移动,并移除当前l的字符
char Slc=S.charAt(l); // 获取l指针在S串中的字符
int SlcTempnum=tempmap.get(Slc); // 得到临时map中该字符的数量
tempmap.put(Slc,SlcTempnum-1); // 将当前字符数-1
if(SlcTempnum==0) tempmap.remove(Slc); // 如果当前字符数为0,移除出map
l++;
}
}
if(resR==Integer.MAX_VALUE) return "";
return S.substring(resL,resR+1);
}
}