题目:76. 最小覆盖子串
思路:双指针+哈希表,时间复杂度0(n+m)。
哈希表记录字符串t中字符出现的情况,ans记录字符的种类数。
使用双指针去遍历字符串s,当ans为0时,说明双指针内的元素已覆盖字符串t的字符。那么只需维护左指针,使长度最短,细节看注释。
C++版本:
class Solution {
public:
string minWindow(string s, string t) {
if(t.size()>s.size()) return "";
// 哈希表记录字符串t中字符出现的情况
unordered_map<char,int> mp;
// ans记录字符的种类数
int ans=0;
for(auto x:t){
mp[x]++;
if(mp[x]==1) ans++;
}
// id是符合要求的子串起始下标,mn是最短的子串
int id=-1,mn=s.size()+5;
for(int l=0,r=0;r<s.size();r++){
//双指针内的元素减1
mp[s[r]]--;
// 为0,说明此字符的数量要求已达标
if(mp[s[r]]==0) ans--;
//cout<<l<<'-'<<r<<endl;
// 如果左指针的元素数量小于0,说明这个元素不需要这么多
while(l<r&&mp[s[l]]<0){
mp[s[l]]++;
l++;
}
// 双指针内的元素已覆盖字符串t的字符
// 维护最短的子串
if(ans==0&&mn>r-l+1){
mn=r-l+1;
id=l;
}
}
if(id==-1) return "";
return s.substr(id,mn);
}
};
JAVA版本:
class Solution {
public String minWindow(String s, String t) {
if(t.length()>s.length()) return "";
Map<Character,Integer> mp=new HashMap<>();
int ans=0;
char[] c=t.toCharArray();
for(char x:c){
mp.put(x,mp.getOrDefault(x,0)+1);
if(mp.get(x)==1) ans++;
}
//System.out.println(ans);
c=s.toCharArray();
int id=-1,mn=s.length()+5;
for(int l=0,r=0;r<c.length;r++){
mp.put(c[r],mp.getOrDefault(c[r],0)-1);
if(mp.get(c[r])==0) ans--;
//System.out.println(l+" "+r+" "+ans);
while(l<r&&mp.get(c[l])<0){
mp.put(c[l],mp.getOrDefault(c[l],0)+1);
l++;
}
if(ans==0&&mn>r-l+1){
mn=r-l+1;
id=l;
}
}
if(id==-1) return "";
return s.substring(id,id+mn);
}
}
GO版本:
func minWindow(s string, t string) string {
n:=len(s)
mp:=map[byte]int{}
ans:=0
for i:=0;i<len(t);i++ {
mp[t[i]]++
if mp[t[i]]==1 {
ans++
}
}
id,mn:=-1,n+5
for l,r:=0,0;r<n;r++ {
mp[s[r]]--;
if mp[s[r]]==0 {
ans--
}
for l<r&&mp[s[l]] < 0 {
mp[s[l]]++
l++;
}
if ans==0 &&mn>r-l+1 {
mn=r-l+1
id=l
}
}
if id==-1 {
return string("")
}
return s[id:id+mn]
}