LeetCode76. 最小覆盖子串 | 刷题打卡

153 阅读1分钟

LeetCode从低效到高效,点击

一、题目描述:

题目要求

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。

注意:如果 s 中存在这样的子串,我们保证它是唯一的答案。

来源:力扣(LeetCode)链接

示例

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"

二、思路分析:

本题是一道经典的双指针题目,本题中要求s中覆盖t所有字符,也就是如果t有两个'a',s的字串只要有a就可以,双指针都从0出发,i指向字串范围的最左边,j指向下一个要获取的位置,左闭右开的区间. j要尽可能向右扫描,每次发现是关键的字符则需要增加对应的windows[s[j]]的值,判断是不是匹配了,如果匹配了就开始尽量增大i的值尝试减少字串长度,直到不能匹配为止,这个时候需要j继续向右扫描.

三、AC 代码:

string minWindow(string s, string t) {
    unordered_map<char,int> window;
    for(auto c:t){
        window[c]=0;
    }
    int match=window.size(),matched=0;
    int i=0,j=0,minlen=0x7FFFFFFF,pos=0;
    while(i<=j&&j<s.size()){
        // 前面的都是加入了也不会产生作用的t里面没有的字母
        while(window.find(s[j])==window.end()&&j<s.size()){
            j++;
        }
        // 下面的j指的最后一个刚加入的位置
        // 这个加入是t里面需要的,j永远指向下一个要进行匹配的值
        window[s[j]]++;
        
        // 如果加入了正好能满足一个字母的需求,匹配个数++
        if(window[s[j]]==1) {
            
            matched++;
        }
        // 指向下一个
        j++;
        // 如果满足匹配,就要考虑如何减少长度
        while(matched==match){
            // 先存一下
            if(minlen>j-i){
                minlen=j-i;
                pos=i;
            }
            // 如果i位置是需要的字符,则需要进一步判断
            if(window.find(s[i])!=window.end()){
                if(window[s[i]]==1){
                    matched--;
                }
                window[s[i]]=max(--window[s[i]],0);
            }
            i++;
        }
    }
    return s.substr(pos,minlen);
}

四、总结:

双指针算法并不都是从左右开始向中心扫描,也可以从一端开始扫描,双指针是对数组左右区间的扫描定位.

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情