【每日刷题】最小覆盖子串

题目地址

https://leetcode-cn.com/problems/minimum-window-substring/

题目描述:最小覆盖子串

给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串。

示例:

输入: S = “ADOBECODEBANC”, T = “ABC”

输出: “BANC”

说明:1. 如果 S 中不存这样的子串,则返回空字符串 “”。2. 如果 S 中存在这样的子串,我们保证它是唯一的答案。

解答

采用 滑动窗口 方法。

在滑动窗口类型的问题中都会有两个指针。一个用于延伸现有窗口的 rightright指针,和一个用于收缩窗口的leftleft 指针。在任意时刻,只有一个指针运动,而另一个保持静止。

本题的解法很符合直觉。我们通过移动right指针不断扩张窗口。当窗口包含全部所需的字符后,如果能收缩,我们就收缩窗口直到得到最小窗口。

答案是最小的可行窗口。

举个例子, S = “ABAACBAB”,T = “ABC”。则问题答案是 “ACB” ,下图是可行窗口中的一个。

在这里插入图片描述

算法步骤:

  1. 初始,left 指针和 right 指针都指向SS的第一个元素.

  2. 将 right 指针右移,扩张窗口,直到得到一个可行窗口,亦即包含 T 的全部字母的窗口。

  3. 得到可行的窗口后,将 left 指针逐个右移,若得到的窗口依然可行,则更新最小窗口大小。

  4. 若窗口不再可行,则跳转至步骤 2。

代码:

class Solution {
public:
    bool isRight( vector<int>& a, vector<int>& b){
        for( int i = 0; i < b.size(); i++)
            if( a[i] < b[i])
                return false;
        return true;
    }
    
    void update( int& res_size, int& begin, int left, int right){
        if( res_size > right - left + 1)
            res_size = right - left + 1, begin = left;
    }
    
    string minWindow(string s, string t) {
        vector<int> record_now(128,0), record_target(128,0);
        //将 t 中的所有字符备份到 record_target 中
        for( auto it:t)
            record_target[it]++;
        
        int res_size = INT_MAX, begin = 0;
        //首先到达第一个边界
        int right = 0;
        for( ; right < s.size(); right++){
            record_now[ s[right]]++;
            if( isRight( record_now, record_target)){
                update( res_size, begin, 0, right);
                break;
            }
        }
        
        for( int left = 0; left < right && right < s.size();){
            record_now[ s[left]]--, left++;

            if( isRight( record_now, record_target))
                update( res_size, begin, left, right);
            else
                for( right++; right < s.size(); right++){
                    record_now[ s[right]]++;
                    if( isRight( record_now, record_target)){
                        update( res_size, begin, left, right);
                        break;
                    } 
                }
        }
        
        if( res_size == INT_MAX)    //此时没有匹配的子串
            return "";
        
        return s.substr( begin, res_size);
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值