给出两个字符串S和T,要求在O(n)的时间复杂度内在S中找出最短的包含T中所有字符的子串。
例如:
S ="ADOBECODEBANC"
T ="ABC"
找出的最短子串为"BANC".
注意:
如果S中没有包含T中所有字符的子串,返回空字符串 “”;
满足条件的子串可能有很多,但是题目保证满足条件的最短的子串唯一。
思路:采用滑动窗口,而且只有首尾都是T的字符的时候才有可能是最小的。当找到一组的时候,要遍历他内部是否有更小的子字符串。
<?php
/**
* @param $S
* @param $T
* @return string
* @brief 采用滑动窗口,最短一定是头和尾都是T中的字符
*/
function minWindow($S, $T) {
$numS = strlen($S);
$numT = strlen($T);
$min = $numS + 1;//比最大还要大,肯定可以被下面的长度覆盖
$retStr = '';
$left = 0;
$right = 0;
//map数组存储T中各个字符的数量
$arrT = array();
for ($i = 0; $i < $numT; $i ++) {
$arrT[$T[$i]] ++;
}
$num = 0;//用来记录找到了几个T中的字符
for ($right = 0; $right < $numS; $right ++) {
print json_encode($arrT) . "\n";
//如果当前位置是T中的字符
if (isset($arrT[$S[$right]])) {
//如果当前字符是T中还没匹配到的字符
if ($arrT[$S[$right]] > 0) {
$num ++;
}
//如果在中间有重复的,这样记录下来,即便后面++,也代表着不缺这个字符
$arrT[$S[$right]] --;
//如果已经全部匹配到T的字符,然后遍历内部所有的left是否有更小的
while ($num == $numT) {
//找到最左边是T中的字符为开始
if (isset($arrT[$S[$left]])) {
//如果是当前最小
if ($right - $left + 1 < $min) {
$min = $right - $left + 1;
$retStr = substr($S, $left, $min);
}
//滑动窗口,把最左边这个字符去掉,向右滑动
$arrT[$S[$left]] ++;
//如果左边去掉的这个在他内部还有的话,继续循环,可以找到里面更小的实现
if ($arrT[$S[$left]] > 0) {
$num --;
}
}
$left ++;
}
}
}
return $retStr;
}
$S = 'ADOBECODEBANC';
$T = 'ABC';
$ret = minWindow($S, $T);
print $ret;