一、题目
二、 示例
三、提示
四、 思路与代码实现
1. 思路
本题, 套用的是滑动窗口算法模板; 初始化左右窗口边界指针(要方便源串取值) left = 0, right = 0, 为什么这样初始化?
若设置窗口索引为左闭右闭
区间, 则这样初始化时,窗口为windows[0, 0], 即初始化时就包含了一个元素; 若设置窗口索引为左开右开
区间, 则这样初始化时,窗口为windows(0, 0), 那么当right像右滑动的一格时候, 窗口windows(0, 1)仍然没有元素, 此时right 指针要多滑动一位才有包含; 以上两种都不方便处理边界; 而左闭右开
区间,当初始化时, 窗口为windows[0, 0), 此时窗口中包含一个元素windows[0],方便处理边界; 使用unordered_map<char, int>
容器来定义windows(窗口)与need, 其中 need 记录 T中字符出现的次数, 而windows则记录窗口中字符的出现次数; 接着先滑动 right 指针来扩大窗口
, 其中若窗口中的字符与need中的字符匹配(数量上也要匹配),则val++(val代表窗口中满足 need 条件的字符个数 例如, T 为ABC
, 而滑动窗口包含为 B
NB
AC); 而收缩窗口的时机
为, 当 val == need.size()
即窗口中包含的字符满足了need条件, 此时窗口已经完全覆盖了子串 T;在这里做子串的更新, 若 right - left 这一范围比之前的 len 长度更小则长度len更新, 且让 start = left; 返回子串为: return len == INT_MAX_LEN ? "" : s.substr(start, len);
2. 代码
class Solution {
public :
string minWindow ( string s, string t) {
const int INT_MAX_LEN = 1e6 ;
unordered_map< char , int > windows, need;
for ( char c : t) need[ c] ++ ;
int left = 0 ;
int right = 0 ;
int val = 0 ;
int start = 0 ;
int s_len = s. size ( ) ;
int len = INT_MAX_LEN;
while ( right < s_len) {
char c = s[ right] ;
right++ ;
if ( need. count ( c) ) {
windows[ c] ++ ;
if ( windows[ c] == need[ c] ) {
val++ ;
}
}
while ( val == need. size ( ) ) {
if ( right - left < len) {
start = left;
len = right - left;
}
char d = s[ left] ;
left++ ;
if ( need. count ( d) ) {
if ( windows[ d] == need[ d] ) {
val-- ;
}
windows[ d] -- ;
}
}
}
return len == INT_MAX_LEN ? "" : s. substr ( start, len) ;
}
} ;
3. 关键思考
滑动窗口算法的关键:
1、什么时候应该扩大窗口? 2、什么时候应该缩小窗口? 3、什么时候应该更新答案?