76. 最小覆盖子串
Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目描述
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。 如果 s 中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入: s = "ADOBECODEBANC", t = "ABC"
输出: "BANC"
具体题目链接: 题目链接
思路:
思路:滑动窗口思路
窗口扩展时寻找可行解,窗口收缩时优化可行解
当滑动窗口可以定长时,一直维护k个长度的滑动窗口即可
当滑动窗口需要不定长时,需要通过特定条件(比如滑动窗口的总和)来判断left和right指针 到底是移动哪个
分析:
求最小子串
思路:
首先要统计一下t里面的字符个数各有多少,使用hash:比如ABC:A:1 B:1 C:1理清种类和个数
维护一个滑动窗口window的hash表:right++的时候 hash[s[i]]++; 当window里面的个数 等于 t的个数时,就使用res 维护一个最小子串
本质上滑动窗口是一种技巧,hash表是一个数据结构
细节:定义一些变量 hash表:维护t的字符的种类和具体的个数 typenum:字符种类的数量
代码:
var minWindow = function(s, t) {
let n = s.length;
let hash = {};
let res = s.length+1;//最小长度
let start = s.length;//最小长度的起始位置
let typenum = 0;
// 使用hash存取t字符串的各字符的个数情况
for(let i=0;i<t.length;i++) {
if(hash[t[i]]==undefined) {
hash[t[i]]=1;
typenum++;
}
else hash[t[i]]++;
}
let left = 0;
let right = 0;
// 这里将left和right定义成左闭右闭区间,right及right之前的数据都是看到了
while(right<n) {//双指针+滑动窗口进行遍历
let rightvalue = s[right];//right指向的字符
if(hash[rightvalue]!= undefined)hash[rightvalue]--;//如果当前字符 在t中有值,就--
if(hash[rightvalue] == 0)typenum--;//如果当前字符 在t中的值为0,说明当前字母种类为0,就--
//滑动窗口里面的种类都满足了覆盖t的字符串
while(typenum == 0) {
//这里为什么错了
if (right - left + 1 < res) { // 窗口宽度如果比minLen小,就更新minLen
res = right - left + 1 ;
start = left; // 更新最小窗口的起点
}
let leftvalue = s[left]; //和right同理
if(hash[leftvalue]!= undefined)hash[leftvalue]++;
if(hash[leftvalue] > 0)typenum++;
//当left当前的字符与t属于无关的,就直接left++
left++// 左指针要右移 收缩窗口
}
right++;// 右指针要右移 加大窗口
}
if(start == s.length)return '';//说明
return s.substring(start, start+res);//截取从start开始的res长度的子串
};
总结:
这是算法系列文章「滑动窗口」的相关题解
类型滑动窗口类型题目,解题方法窗口扩展时寻找可行解,窗口收缩时优化可行解