力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
题目描述
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
注意:
-
对于
t
中重复字符,我们寻找的子字符串中该字符数量必须不少于t
中该字符数量。 -
如果
s
中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = "ADOBECODEBANC", t = "ABC" 输出:"BANC" 解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。
解题思路
这道题可以用滑动窗口来解决,当窗口中的子串包含t中的所有字符时,计算当前窗口的长度,和原来窗口比较,最后返回最小的窗口中的字符串
1.定义left,right初始值都为0,count表示有效字符的个数,count表示有效字符的种类
定义hash1 表示窗口中的字符串,hash2 表示 t 的字符
首先将 t 中的字符根据键值对放到 hash2 中
移动right,并将right指向的字符放到 hash1 中,放到 hash1之后判断 hash1.get(right) 是否等于 hash2.get(right),如果相等,则是有效字符,count++,不相等则是无效字符
2.直到 count == hash2.size(),此时计算窗口的长度,并与原来长度比较,选较小的,然后将窗口的左右下标存到临时变量里面
3.然后移动left,移动前判断 hash1.get[left] 是否等于 hash2.get(left),如果相等,则证明当前是有效字符,count--,否则count不变。
然后hash.get(left)-- ,left++。
left 一直移动到下一次hash1.get(left) == hash2.get(left)
4.重复步骤1、2、3直到right到达最后
代码
当使用hashMap的接口时,LeetCode上最后一个会通不过,这是因为
java中使用Map时,里面的类型时Integer,因为Integer是对象,所以会缓存频繁使用的数值,范围是-128~127,在这个范围内的数会直接返回缓存值。超过了会new一个对象,所以在get的时候使用 .intValue()即可避免这种情况
hash2.put(t.charAt(i),hash2.getOrDefault(t.charAt(i),0).intValue()+1);
这个问题困扰了我将近4个小时的时间,希望看到这里的小伙伴可以避免出现这个问题
public String minWindow(String s, String t) {
int left = 0;
int right = 0;
int count = 0;//表示当前有效字符
HashMap<Character,Integer> hash1 = new HashMap<>();
HashMap<Character,Integer> hash2 = new HashMap<>();
int len = Integer.MAX_VALUE;//当前最小的窗口
int tmpl = -1;//暂存最小窗口的left下标
//将t存放到hash2
for (int i = 0;i<t.length();i++){
hash2.put(t.charAt(i),hash2.getOrDefault(t.charAt(i),0).intValue()+1);
}
while (right<s.length()){
char charR = s.charAt(right);
hash1.put(charR,hash1.getOrDefault(charR,0).intValue()+1);//将right指向的字符存到hash1
if (hash1.get(charR).intValue() == hash2.getOrDefault(charR,0).intValue()){
//此时是有效字符
count++;
}
right++;
//窗口成立时
while (count == hash2.size()){
//先更新一下窗口
if(right-left < len){
len = right-left;
tmpl = left;
}
//移动left指针,不成立
if (hash1.get(s.charAt(left)).intValue() == hash2.getOrDefault(s.charAt(left),0).intValue()){
count--;
}
hash1.put(s.charAt(left),hash1.get(s.charAt(left)).intValue()-1);
left++;
}
}
//最后返回 tmpl 和 tmpr之间的数
// char[] str1 = new char[len];
if (tmpl == -1){
return new String();
}
return s.substring(tmpl,tmpl+len);
}
//大佬的代码
public String minWindow1(String ss, String tt) {
char[] s = ss.toCharArray();
char[] t = tt.toCharArray();
int[] hash1 = new int[128];//用数组模拟哈希表
int kinds = 0;//标记t中有多少种字符
for (char ch:t){
if (hash1[ch]==0){
kinds++;
}
hash1[ch]++;
}
int[] hash2 = new int[128];
int minlen = Integer.MAX_VALUE;
int begin = -1;
for (int left = 0,right = 0,count = 0;right<s.length;right++){
char in = s[right];
hash2[in]++;
if (hash2[in]==hash1[in]) count++;
while (kinds==count){
if (right-left+1<minlen){
begin=left;
minlen = right-left+1;
}
char out = s[left];
left++;
if (hash2[out]==hash1[out]){
count--;
}
hash2[out]--;
}
}
if (begin == -1){
return new String();
}else {
return ss.substring(begin,begin+minlen);
}
}