题目
给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串。
示例:
输入: S = “ADOBECODEBANC”, T = “ABC”
输出: “BANC”
说明:
如果 S 中不存这样的子串,则返回空字符串 “”。
如果 S 中存在这样的子串,我们保证它是唯一的答案。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-window-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
使用哈希表存储字符与出现次数的关系,维护一个哈希表win,来记录左右指针指向的区间内的字符出现情况,另一个哈希表sub则保存子串的情况(sub总是不变)
区间问题一律双指针,但是要注意一些区间转化时候细节:
1.明确区间转化的条件
- 如果满足条件,左端点++
- 如果未满足条件,右端点++
这题的条件就是:如果对于子串所有字符,在区间中出现的次数都大于等于他们在子串中出现的次数
2.如何维护区间(的哈希表)
- 如果一个新字符进来区间,需要在哈希表对应的映射+1
- 如果一个字符离开区间(左端点++的时候),需要对应哈希表项-1
注意:维护必须总是发生在区间端点移动之后进行
3.边界条件
根据区间转移性质,如果不满足,那么推进右端点
右端点如果走到终点,那么直接结束,因为大的区间不满足,子区间更加不满足了(视情况而定,有的题目要特殊考虑)
4.初始区间
对于这题,一开始我们需要将<主串的第一个字符,出现一次>
放进区间,完成哈希表的初始化
代码
注意哈希表的维护总是发生在区间端点变动时,否则会导致错误的计数
class Solution {
public:
string minWindow(string s, string t)
{
if(s.length()==0) return "";
unordered_map<char, int> win;
unordered_map<char, int> sub;
for(int i=0; i<t.length(); i++) sub[t[i]]++;
int l=0, r=0, len=INT_MAX, n=s.length();
string ans = "";
win.insert(pair<char,int>(s[0], 1));
while(r<n)
{
int cnt = 0;
for(auto it=sub.begin(); it!=sub.end(); it++)
if(win[it->first]>0 && win[it->first]>=it->second) cnt++;
if(cnt==sub.size())
{
if(r-l+1<len)
{
ans = string(s.begin()+l, s.begin()+r+1);
len = r-l+1;
}
win[s[l]]--; l++;
}
else {r++; win[s[r]]++;}
}
return ans;
}
};