给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。
示例:
输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"
说明:
- 如果 S 中不存这样的子串,则返回空字符串
""
。 - 如果 S 中存在这样的子串,我们保证它是唯一的答案。
思路:
- 首先处理特殊情况 字符串为空 已经s串小于t串的长度的情况;
- 再者将t中的字符串存入一个查找表dict中 方便每个字符出现的次数比较;并且设置一个 匹配的总数total=lent;
- 用双指针循环便利字符串S
- 如果s中的某一个字符 在字典中存在的话 那么字典中的次数减去1,待匹配的个数也减去1;dict[s[right]]-->0 total--;
- 如果当total==0的时候 说明进行一次匹配完毕 找到一个解;这时候需要比较当前滑动窗口的长度和前面存储的min的大小进行比较 然后再对min和start进行更新;
- 如果匹配完毕之后 再进行 left左移进行缩进;if(++dict[left++]>0) total++;
- 这句话 寓意很丰富;注意当前dict[lleft]==0代表的是 当前是字符是字典中的字符;所以一开始当前字符的数量应该是一个非0的数 如果出现一次就是1 多次就是一个正数;当进行匹配完成之后 进行过1次或者多次dict[s[right]]-- 和total--之后;当前字符的dict的值为0;如果说这个字符是没有出现过的 那么这个字符的值为负数 进行+1操作之后还是不大于0 ;
- 所以说如果说上述的判断>0代表的是 这个字符是字符串t中的一个字符;把这个字符去除之后 会不包含全部的t 所以total需要自增 total++;
- 如果说<0; 就不自增;
- 然后left++;表示的是 将当前的left往后移动一位;
- 这句话 寓意很丰富;注意当前dict[lleft]==0代表的是 当前是字符是字典中的字符;所以一开始当前字符的数量应该是一个非0的数 如果出现一次就是1 多次就是一个正数;当进行匹配完成之后 进行过1次或者多次dict[s[right]]-- 和total--之后;当前字符的dict的值为0;如果说这个字符是没有出现过的 那么这个字符的值为负数 进行+1操作之后还是不大于0 ;
CODE:::
class Solution {
public:
string minWindow(string s, string t)
{
int lens=s.length();
int lent=t.length();
if(lens==0||lent==0||lens<lent)
return "";
vector<int>dict(128,0);//查找表的构建;
for(auto ch:t)
dict[ch]++;
int start=0;//匹配之后的字符串 起始的位置;
int total=lent;//待匹配的元素的个数;
int min=INT_MAX;//滑动窗口的长度或者说是其中的元素的个数;
for(int left=0,right=0;right<lens;right++)
{
if(dict[s[right]]-- >0)//如果说这个字符在 字典中 那么次数-1;toal-1;
total--;
while(total==0)//total==0表示的是一次匹配完成 ;那么需要比较min和当前滑动窗口的长度;
{
if(right-left+1<min)//更新min和start;
{
min=right-left+1;
start=left;
}
if(++dict[s[left++]]>0)//这句话特别的重要; 表示的是一次匹配完成之后的 left移动;是否还包含全部的字符(也就是当前的字符是不是字典中的元素);不包含 total++;包含不处理;
total++;
}
}
return min==INT_MAX?"":s.substr(start,min);
}
};