您的位置:首页 > 编程语言 > C语言/C++

【Minimum Window】cpp

2015-06-08 15:13 337 查看
题目:

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. 动态更新最小区间。

主要参考:

/article/4879682.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);
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: