leetcode 76. 最小覆盖子串 (数组中的问题 滑动窗口和查找表的组合)

给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。

示例:

输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"

说明:

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

思路:

  1. 首先处理特殊情况  字符串为空 已经s串小于t串的长度的情况;
  2. 再者将t中的字符串存入一个查找表dict中 方便每个字符出现的次数比较;并且设置一个 匹配的总数total=lent;
  3. 用双指针循环便利字符串S
    1. 如果s中的某一个字符 在字典中存在的话  那么字典中的次数减去1,待匹配的个数也减去1;dict[s[right]]-->0 total--;
    2. 如果当total==0的时候 说明进行一次匹配完毕 找到一个解;这时候需要比较当前滑动窗口的长度和前面存储的min的大小进行比较  然后再对min和start进行更新;
    3. 如果匹配完毕之后 再进行 left左移进行缩进;if(++dict[left++]>0) total++;
      1. 这句话 寓意很丰富;注意当前dict[lleft]==0代表的是 当前是字符是字典中的字符;所以一开始当前字符的数量应该是一个非0的数  如果出现一次就是1 多次就是一个正数;当进行匹配完成之后 进行过1次或者多次dict[s[right]]--   和total--之后;当前字符的dict的值为0;如果说这个字符是没有出现过的 那么这个字符的值为负数  进行+1操作之后还是不大于0 ;
        1. 所以说如果说上述的判断>0代表的是 这个字符是字符串t中的一个字符;把这个字符去除之后 会不包含全部的t  所以total需要自增  total++;
        2. 如果说<0;  就不自增;
      2. 然后left++;表示的是 将当前的left往后移动一位;


CODE:::

class Solution {
public:
    string minWindow(string s, string t) 
    {
        int lens=s.length();
        int lent=t.length();
        if(lens==0||lent==0||lens<lent)
            return "";
        vector<int>dict(128,0);//查找表的构建;
        for(auto ch:t)
            dict[ch]++;
        int start=0;//匹配之后的字符串 起始的位置;
        int total=lent;//待匹配的元素的个数;
        int min=INT_MAX;//滑动窗口的长度或者说是其中的元素的个数;
        for(int left=0,right=0;right<lens;right++)
        {
            if(dict[s[right]]-- >0)//如果说这个字符在 字典中 那么次数-1;toal-1;
                total--;
            while(total==0)//total==0表示的是一次匹配完成 ;那么需要比较min和当前滑动窗口的长度;
            {
                if(right-left+1<min)//更新min和start;
                {
                    min=right-left+1;
                    start=left;
                }
                if(++dict[s[left++]]>0)//这句话特别的重要; 表示的是一次匹配完成之后的 left移动;是否还包含全部的字符(也就是当前的字符是不是字典中的元素);不包含 total++;包含不处理;
                    total++;
            }
        }
        return min==INT_MAX?"":s.substr(start,min);
    }
};

猜你喜欢

转载自blog.csdn.net/langxue4516/article/details/81381476