最小窗口子字符串
给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。
示例:
输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"
说明:
- 如果 S 中不存这样的子串,则返回空字符串
""
。 - 如果 S 中存在这样的子串,我们保证它是唯一的答案。
分析
核心思想: 首尾双指针,尾指针右移扩张找到包含目标字符的子串,首指针右移收缩使字串最小。
做法:
- 预扫描目标字符串 t,哈希表存储出现的字符及其个数
- 遍历 源字符串s,遇到 t 中字符,其哈希值减一,直到当前子串包含了所有 t 中的字符,记录该子串,并更新最小子串。
- 收缩该子串,首指针右移
- 忽略不在 t 中的字符。
- 当 子串中出现某字符次数多于 t 中该字符的个数,也可忽略该字符。比如 找到某子串 AACD ,t = ACD,则第一个A也可忽略。
- 直到右移至 该子串缺失某字符。如 ACD -> CD
- 重复2,直到遍历到s尾
代码
class Solution {
public String minWindow(String s, String t) {
if(s.length()<t.length() || s.length()==0 || s ==null || t == null || t.length() == 0)
return "";
//模拟哈希表,存储目标字符串的各个字符的个数
int[] map = new int[255];
for(int i=0;i<t.length();i++){
map[t.charAt(i)]++;
}
//双指针遍历源字符串s
int begin = 0,end = 0;
//最小字符串的起点
int minBegin = 0;
//最小字符串的长度
int res = Integer.MAX_VALUE;
//用来记录匹配到字符的个数,如果count == t.length()意味着找到一个匹配的字串
int count = 0;
//遍历
while(end < s.length()){
//这里可理解为缺失字符的个数,==0时则表示 这个字符匹配够了,==1则表示仍需要再匹配一个该字符
if(map[s.charAt(end)]>0)
count ++;
//不需要匹配的字符,其值此时小于0
map[s.charAt(end)]--;
//尾指针右移
end++;
//匹配到一个字串
while(count == t.length()){
//比较字串长度,更新字串信息
if(end - begin < res){
res = end - begin;
minBegin = begin;
}
//如果首指针对应字符是目标字符之一,则跳出循环
if(map[s.charAt(begin)] == 0)
count--;
//首指针对应字符的哈希值还原
map[s.charAt(begin)]++;
//首指针右移
begin++;
}
}
return res == Integer.MAX_VALUE? "" :s.substring(minBegin,minBegin + res);
}
}