8.最小覆盖子串
我们很容易就能想到暴力解法,就是暴力枚举:
我们找到满足条件的这个子串后,就要将left++,然后right回到left的位置开始遍历,寻找下一个满足条件的子串,期间用哈希表来统计,判断是否满足条件
我们在暴力解法上进行优化:
(1)实际上当找到一个满足条件的子串后,right没必要回到left的位置,因为哈希表中已经存有left到right的信息
(2)left不只是简单的++,因为left++后,可能会出现2种情况:
①子串还是满足条件,那么left还要继续++,
②子串不满足条件,那么left不用在继续++
因此这种双指针同向运动的题目就是我们熟悉的滑动窗口
我们用in来表示进窗口的元素,out来表示出窗口的元素,hash1记录t中每个字符的个数,hash2记录窗口中每个字符的个数
(1)进窗口:hash2(in)++
(2)判断 :判断hash1和hash2中记录的字符情况是否一致,是的话更新结果,并出窗口
(3)出窗口:hash2(out)++
对于判断的优化:我们在前面的题目做过类似的判断优化方法,即用count来记录有效字符的个数
但是在这道题中两个哈希表不是简单的一一对应的关系,hash2中的字符可能会出现多次
所以我们应该判断的是字符的种类,即当hash1[in] == hash2[in]时,count++;而用kinds记录t中字符的种类,当kinds == count时,更新条件
题解:
java
class Solution {
public static String minWindow(String s, String t) {
int[] hash2 = new int[80];
int[] hash1 = new int[80];
int kinds = 0;
for(char c : t.toCharArray()){
if(hash1[c - 'A']++ == 0){
kinds++;
}
}
int minLen = s.length() + 1;
int len = s.length();
int begin = -1;
for(int left = 0,right = 0,count = 0;right < s.length();right++){
char in = s.charAt(right);
hash2[in - 'A']++;
if(hash2[in - 'A'] == hash1[in - 'A']){
count++;
}
while(count == kinds && left <= right){
int tmp = right - left + 1;
if(tmp < minLen){
begin = left;
minLen = tmp;
}
char out = s.charAt(left);
if(hash2[out - 'A'] == hash1[out - 'A']){
count--;
}
hash2[out - 'A']--;
left++;
}
}
return minLen == s.length()+1 ? "" : s.substring(begin,begin+minLen);
}
}