《leetCode-php》最小窗口子字符串

给出两个字符串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;
发布了284 篇原创文章 · 获赞 32 · 访问量 49万+

猜你喜欢

转载自blog.csdn.net/less_cold/article/details/102810354