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

本文详细解析了如何使用滑动窗口算法,在O(n)的时间复杂度内从字符串S中找出包含字符串T所有字符的最短子串。通过具体示例说明了算法的实现过程,并提供了完整的PHP代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给出两个字符串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;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值