给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字符的最小子串。
示例:
输入: S = “ADOBECODEBANC”, T = “ABC”
输出: “BANC”
说明:
如果 S 中不存这样的子串,则返回空字符串 “”。
如果 S 中存在这样的子串,我们保证它是唯一的答案。
通过次数57,799提交次数152,286
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-window-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:hash+滑动窗口
首先题目是一定要用滑动窗口来做的,那么第一步就是思考如何查看滑动窗口内部的元素是否满足要求,对于本题目而言,可以先将目标字符串hash到int类型的数组之中,之后在遍历的过程之中,动态的维护窗口的int类型的hash数组,之后就可以通过比较两个数组来判断是否满足要求。其次,对于滑动窗口的移动来说,考虑对滑动窗口的结尾(即右侧)进行遍历,同时维护一个begin为滑动窗口的开端,每次遍历首先考虑当前的滑动窗口是否能够满足要求,如果不能则遍历下一个右端点,如果能够满足要求,那么尽量的将左端点向右移动以得到最短的滑动窗口,移动的条件是:1.当前左端点指向的元素不在目标字符串中;2.当前左端点指向的元素出现的次数大于目标字符串中该元素出现的次数。当不能继续移动的时候,比较此时的长度和记录的长度,存储下较小的长度和与该长度对应的begin和i值,以便返回结果。最后根据记录返回结果即可。
注:1. 对于字母的hash可以使用int类型的数组,而不必使用map。
2. 可以使用一个vector数组记录目标字符串出现的字符,以避免每次比对是否满足要求的时候都需要遍历整个数组;
3. 要考虑特殊情况,如没有满足要求的子串(将end设置为特殊的值);
4. 在leetcode中,进行输出耗时很长,所以在提交之前需要清除所有用于debug的输出语句。
class Solution {
public:
string minWindow(string s, string t) {
int tl = t.size();
int sl = s.size();
if(tl>sl)return "";
int charmap_s[128];
memset(charmap_s,0,sizeof(charmap_s));
int charmap_t[128];
memset(charmap_t,0,sizeof(charmap_t));
vector<int> tv;
for(int i = 0;i<tl;i++)
{
charmap_t[t[i]]++;
}
for(int i = 0;i<128;i++)
{
if(charmap_t[i]>0)
tv.push_back(i);
}
int begin = 0;
int start = 0;
int end = -1;
int min = sl;
for(int i = 0;i<sl;i++)
{
charmap_s[s[i]]++;
if(!isMatch(charmap_s,charmap_t,tv))
{
continue;
}
else
{
while(begin<i&&(charmap_t[s[begin]]==0||charmap_s[s[begin]]>charmap_t[s[begin]]))
{
charmap_s[s[begin]]--;
begin++;
}
if((i-begin)<min)
{
end = i;
start = begin;
min = end-begin;
}
}
}
string ret = "";
if(end==-1)return ret;
for(int i = start;i<=end;i++)
{
ret+=s[i];
}
return ret;
}
bool isMatch(int* s,int* t,vector<int>& tv)
{
for(int i = 0;i<tv.size();i++)
{
int index = tv[i];
if(s[index]<t[index])return false;
}
return true;
}
};