题目:
Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).
For example,
S = "ADOBECODEBANC"
T = "ABC"
Minimum window is "BANC"
.
Note:
If there is no such window in S that covers all characters in T, return the emtpy string ""
.
If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.
代码:
class Solution { public: string minWindow(string s, string t) { if (s.empty() && t.empty() ) return ""; if (s.size()<t.size()) return ""; const int ASCII_MAX = 256; // record how much times a char occurs in t int t_char_count[ASCII_MAX] = {0}; for ( int i=0; i<t.size(); ++i ) { t_char_count[(int)t[i]]++; } // record how much times a char occurs in s int s_char_count[ASCII_MAX] = {0}; // global min begin and end index for minimum interval int begin_min=-1, end_min=s.size(); // local min begin ( no need to record local min end ,because it is 'i' ) int begin = 0; int match_size = 0; for ( int i=0; i<s.size(); ++i ) { // current interval not match && current char in t if ( t_char_count[(int)s[i]]>0 ) { //cout << s[i] << ":" << t_char_count[s[i]] << endl; s_char_count[(int)s[i]]++; // if a char occurs more times in current interval s than in t, can not increase match_size if ( s_char_count[(int)s[i]]<=t_char_count[(int)s[i]] ) match_size++; } if ( match_size==t.size() ) { // move begin forward untill not match while ( begin<=i ) { // only address chars not in t if ( s_char_count[(int)s[begin]]>0 ) { if ( s_char_count[(int)s[begin]]-1<t_char_count[(int)s[begin]] ) { //cout << s_char_count[s[begin]] << endl; match_size--; break; } s_char_count[(int)s[begin]]--; } begin++; } s_char_count[(int)s[begin]]--; // update global min begin and end if ( end_min-begin_min > i-begin ) { end_min = i; begin_min = begin; } begin++; } } if( end_min-begin_min>s.size() ) return ""; return s.substr(begin_min,end_min-begin_min+1); } };
tips:
曾经以为这种题比较简答,实际上不带算法模板套路的题才是最费神的。
这道题一开始的思路是记录t中每个字符最左边到哪最右边到哪,然后再云云;这个想法不太靠谱。
如果是bruce force暴力解法,时间复杂度可以是O(n²)的:
1. 遍历每个位置,以每个位置为中心,往左右走,直到包含所有的元素,取最短的。
2. 取所有interval中最短的。
可以AC的解法思路如下:
1. 维护几个核心变量:
a)t中每个字符出现了几次(t_char_count)
b) s中当前区间里面,t中每个字符出现了几次(s_char_count)
c) s当前区间是否满足包含t(match_size)
2. 这道题思路很有趣:先找满足包含t的区间;一旦找到了这样的区间,再缩小这样的区间。
缩减区间的方法:后面的指针保持不动,前面的指针往后移动,直到match_size < t.size(),则证明当前区间已经是最小的满足条件的区间了。
3. 动态更新最小区间。
主要参考:
http://www.cnblogs.com/TenosDoIt/p/3461301.html
http://fisherlei.blogspot.sg/2012/12/leetcode-minimum-window-substring.html
============================================
第二次过这道题,静下心来码。
class Solution { public: string minWindow(string s, string t) { int t_counts[256] = {0}; int s_counts[256] = {0}; for ( int i=0; i<t.size(); ++i ) t_counts[(int)t[i]]++; int matchTime = 0; int begin = -1; int end = s.size(); int b = 0; for ( int i=0; i<s.size(); ++i ) { // only address character occurs in string t if ( t_counts[(int)s[i]]>0 ) { s_counts[(int)s[i]]++; // after s_count add one change matchTime if ( s_counts[(int)s[i]]<=t_counts[(int)s[i]] ) matchTime++; } // when there is a window, then minimisze it if ( matchTime==t.size() ) { while ( b<=i ) { // only address charatcers occurs in string t if ( s_counts[(int)s[b]]>0 ) { // if move over 'begin then 'can not keep window if ( s_counts[(int)s[b]]-1 < t_counts[(int)s[b]] ) { matchTime--; break; } s_counts[(int)s[b]]--; } b++; } if ( i-b < end-begin ) { begin = b; end = i; } s_counts[(int)s[b]]--; b++; } } if ( end-begin>s.size() ) return ""; return s.substr(begin, end-begin+1); } };