LeetCode76:最小覆盖子串

给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串。

示例:

输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"
说明:

如果 S 中不存这样的子串,则返回空字符串 ""。
如果 S 中存在这样的子串,我们保证它是唯一的答案。

 

基本思路:

  利用双指针left和 right构造一个窗口,使窗口内的串包含T子串,同时更新当前最短长度。更新完毕后当前窗口的串一定是包含T子串所有字符的,在这一基础上缩小窗口,将left指针右移,直到当前窗口不满足要求,在这一右移的过程中要同步更新最短长度。

  当前的窗口已不满足题目要求,则此时移动right指针,右移使窗口继续满足要求。

  循环这一过程,直到right>=s.size()。

 

基本的思路解决后,现在唯一的问题就是如何才能判断一个主串中无序的含有T串中所有字符。

  我们使用两个unordered_map<char,int>哈希表need和window;need用于记录T中所有的字符及对应字符出现的次数,window用于记录当前主串中属于T串的字符及出现的次数。再使用一个变量match用于统计window中与need中字符出现次数一致的元素的数量,比如T中有一个元素b,出现了3次,则need[b]=3,则如果window[b]>=3,则令match++,说明又有一个元素匹配上了。

 

代码:

class Solution {
public:
    string minWindow(string s, string t) {
		if(s.empty()||t.empty()||s.size()<t.size())
			return string();
        unordered_map<char,int> need;
		unordered_map<char,int> window;
		for(int i=0;i<t.size();i++)
			need[t[i]]++;
		int left=0,right=0;
		int match=0;int min=INT_MAX;
		int l=0;
		while(right<s.size())
		{
			char c1=s[right];
			if(need.count(c1))
			{
				window[c1]++;
				match=(window[c1]==need[c1])?(match+1):(match);
			}
			right++;
			while(match==need.size())
			{
				char c2=s[left];
				if((right-left)<min)
				{
					min=right-left;
					l=left;
				}
				if(window.count(c2))
				{
					window[c2]--;
					if(window[c2]<need[c2])
						match--;
				}
				left++;
			}
		}
		if(min==INT_MAX)
			return string();
		return s.substr(l,min);
    }
};

 这个题目为我们提供了一种用滑动窗口法解题的一般性方法:

 主体为一个while循环,while中分为两部分,上部分为向右移动right使该窗口满足要求。下部分是缩小窗口使该窗口不满足要求。

 通过循环来遍历整个过程中所有满足要求的窗口,并更新所得结果。

int left = 0, right = 0;

while (right < s.size()) {
    window.add(s[right]);
    right++;
    
    while (valid) {
        window.remove(s[left]);
        left++;
    }
}

  

  

posted @ 2019-08-07 09:51  李湘沅  阅读(125)  评论(0编辑  收藏  举报