1.题目描述
2.思路
滑动窗口,用两个哈希表来记录当前t中字符的数量和滑动窗口的数量。
窗口滑动的同时要记录有效字符的数量。
ht:字符串t的哈希表。
hs:字符串s的哈希表。
cnt:代表窗口滑动时的有效字符的数量。
所以,
(1)i指针在第1个元素
ht:{A:1,B:1,C:1}
hs中设置两个指针,i和j,同时指向第一个元素。每次循环进行3个操作,把当前字符加入到窗口中,如果加到hs中的字符没有超过ht中字符的数量说明是有效字符,所以cnt+1。因为在窗口加入了新的字符,所以窗口左侧中会存在冗余字符所以要删,所以要右移窗口的左边界。如果cnt的数值等于ht的长度,说明已经窗口已经覆盖t的所有字符串.
hs{A:1}
cnt=1
(2)i指针在第3个元素
ht:{A:1,B:1,C:1}
hs{A:1,B:1}
cnt=2
(3)i指针在第3个元素
ht:{A:1,B:1,C:1}
hs{A:2,B:1}
cnt=2
当前hs窗口字符A超过了ht所需要的A的元素的个数,所以j向后移动。同时hs窗口A中的数量-1.
时间复杂度是O(n)
3.代码实现
class Solution {
public String minWindow(String s, String t) {
HashMap<Character,Integer> ht=new HashMap<>();
HashMap<Character,Integer> hs=new HashMap<>();
for(int i=0;i<t.length();i++)
{
//把t字符和字符的个数,放入到ht的哈希表中
//记得字符串取字符用 字符串.charAt(); 在哈希表中根据字母找它的值用 字符串.getOrDefault(字符,0)
//ht.put(t.charAt(i),ht.getOrDefault(t.charAt(i),0)+1);
char c=t.charAt(i);
ht.put(c,ht.getOrDefault(c,0)+1);
}
//定义最小覆盖子串
String ans="";
//统计有效字符
int cnt=0;
//遍历hs哈希表
for(int i=0,j=0;i<s.length();i++)
{
char c=s.charAt(i);
hs.put(c,hs.getOrDefault(c,0)+1);
//如果hs滑动窗口的当前字符的个数小于等于ht哈希表的该字符的个数,说明滑动窗口还没完全覆盖t字符串的字符,所以有效字符继续++
if(hs.get(c)<=ht.getOrDefault(c,0))
{
cnt++;
}
//如果滑动窗口hs中某个字符的个数大于ht中该字符的个数,移动j指针,缩小窗口,删除冗余字符
while(j<=i&&hs.getOrDefault(s.charAt(j),0)>ht.getOrDefault(s.charAt(j),0))
{
hs.put(s.charAt(j),hs.get(s.charAt(j))-1);
j++;
}
//判断是否找到覆盖子串
if(cnt==t.length())
{
if(ans.isEmpty()||ans.length()>i-j+1)
{
ans=s.substring(j,i+1);
// 更新答案为 s[j..i](注意 substring 的右端是开区间,所以用 i+1)。
}
}
}
return ans;
}
}