题目:
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
注意:如果 s 中存在这样的子串,我们保证它是唯一的答案。
思路:
- 本题所采用方法为滑动窗口,即设置两个指针
left和right
来表示当前窗口的左右界限,我们可以设置一个need
数组,索引代表字符,索引在数组中的值代表还需要几个当前字符才能符合t
的标准 - 第一步:每次先移动
right
指针,碰到一个值就让need[s.charAt(right)]--
,如果当前字符存在于目标字符串t
中,那么也让sum--
,直到sum==0
,此时说明当前滑动窗口已经包含了所有目标字符串t
- 第二步:第一步走完之后,就该移动
left
指针了,因为刚才right
指针走过的位置中可能存在不需要的字符,通过移动left
指针可以缩小当前滑动窗口的范围,直到碰到第一个在字符串t
中出现的字符,这时的一个最小滑动窗口区间就出现了,但他并不一定是最终结果,因为后面可能还会存在比当前滑动窗口区间还要小的情况。 - 第三步:将第二步找到的第一个存在于目标串
t
中的字符从need数组
中剔除(need[s.charAt(left)]++
,表示当前滑动窗口还需要这个字符),并继续移动right
指针重复刚才的第一步,直到right指针走到s字符串的最后
,这样整个字符串的最优结果就出现了
以下为代码+注释:
public String minWindow(String s, String t) {
// 滑动窗口
// 首先设置一个need[]数组,索引为字符的int类型,数值代表需要几个该字符
int[] need = new int[128];
int slen = s.length();
int tlen = t.length();
// 先将目标字符串t遍历一遍,将需要的字符在need数组中更新相应的值
// 这样如果need数组中的值都小于等于0了,就说明当前窗口已经将需要的东西包含完了,没有需要的字符了
for(int i = 0; i < tlen; i++){
need[t.charAt(i)]++;
}
// 第一步:设置两个指针,首先移动右指针,并维护一个sum表示需要的字母总和,
// 每碰到一个需要的字符,就将need中对应字符的值--,并将sum--,如果sum为0,说明不需要字母了,当前滑动窗口已经包含t的所有字母
// 第二步:这个时候就要移动左指针,因为左边区域可能有很多不需要的字母,我们需要将他们删除来求出最小的滑动窗口大小,并设置一个start
// 第三步:根据start索引以及size大小截取并返回最终结果,size表示最小包含所有t中字母的滑动窗口大小,start代表该情况下滑动窗口的第一个索引位置
int left = 0, right = 0, sum = tlen, size = Integer.MAX_VALUE, start = 0;
while(right < slen){
// 如果该字母恰好是需要的字母,就将sum--,也就是还需要查找的字母数量--
if(need[s.charAt(right)] > 0){
sum--;
}
// 不管该字母是否需要,都要将它对应的need数组--
need[s.charAt(right)]--;
// 如果sum为0,说明t中所有字母都包含了,这时就要移动左指针了
if(sum == 0){
while(left < right && need[s.charAt(left)] < 0){
need[s.charAt(left)]++;
left++;
}
// 走到这,说明走到了第一个need值为0的地方(因为不存在于t中的字母经过right指针向右移动时的--,他们的need对应值肯定是小于0的),也就是第一个在t中存在的字母
// 那么就要将当前情况下的滑动窗口大小和size也就是记录大小作比较,如果这个更小,那么就进行更新
if(right - left + 1 < size){
// 同时更新size,并将开始索引start置为第一个目标字母所在索引
size = right - left + 1;
start = left;
}
// 然后将第一个目标字母从华东窗口中剔除,也就是将该字母对应的need值加1,说明滑动窗口中还需要该字母,进行下一个新的滑动窗口的寻找
need[s.charAt(left)]++;
sum++;
left++;
}
right++;
}
// 如果size为默认初始值,说明就没有符合条件的滑动窗口,返回空串,否则,返回以start索引开头的最小串
return size == Integer.MAX_VALUE ? "" : s.substring(start, start + size);
}
笔者也在不断学习,如有错误,欢迎指正!