LeetCode:76 最小覆盖子串 哈希表+双指针 双指针总结

题目

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

示例:
输入: S = “ADOBECODEBANC”, T = “ABC”
输出: “BANC”
说明:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-window-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

使用哈希表存储字符与出现次数的关系,维护一个哈希表win,来记录左右指针指向的区间内的字符出现情况,另一个哈希表sub则保存子串的情况(sub总是不变)

区间问题一律双指针,但是要注意一些区间转化时候细节:

1.明确区间转化的条件

  • 如果满足条件,左端点++
  • 如果未满足条件,右端点++

这题的条件就是:如果对于子串所有字符,在区间中出现的次数都大于等于他们在子串中出现的次数

2.如何维护区间(的哈希表)

  • 如果一个新字符进来区间,需要在哈希表对应的映射+1
  • 如果一个字符离开区间(左端点++的时候),需要对应哈希表项-1

注意:维护必须总是发生在区间端点移动之后进行

3.边界条件

根据区间转移性质,如果不满足,那么推进右端点

右端点如果走到终点,那么直接结束,因为大的区间不满足,子区间更加不满足了(视情况而定,有的题目要特殊考虑)

4.初始区间

对于这题,一开始我们需要将<主串的第一个字符,出现一次>放进区间,完成哈希表的初始化

代码

注意哈希表的维护总是发生在区间端点变动时,否则会导致错误的计数

class Solution {
public:
    string minWindow(string s, string t)
    {
        if(s.length()==0) return "";
        unordered_map<char, int> win;
        unordered_map<char, int> sub;
        for(int i=0; i<t.length(); i++) sub[t[i]]++;
        int l=0, r=0, len=INT_MAX, n=s.length();
        string ans = "";
        win.insert(pair<char,int>(s[0], 1));
        while(r<n)
        {
            int cnt = 0;
            for(auto it=sub.begin(); it!=sub.end(); it++)
                if(win[it->first]>0 && win[it->first]>=it->second) cnt++;
            if(cnt==sub.size())
            {
                if(r-l+1<len) 
                {
                    ans = string(s.begin()+l, s.begin()+r+1); 
                    len = r-l+1;
                }
                win[s[l]]--; l++;
            }
            else {r++; win[s[r]]++;}
        }
        return ans;
    }
};
发布了199 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44176696/article/details/104720233
今日推荐