zoukankan      html  css  js  c++  java
  • LeetCode——727.Minimum Window Subsequence

    一.题目链接:https://leetcode.com/problems/minimum-window-substring/

    二.题目大意:

     给定两个字符串S和T,要求从S中找出包含T中所有字母的最短子串,同时要求时间复杂度为O(n)。

    三.题解:

    这道看上去和https://leetcode.com/problems/longest-substring-without-repeating-characters最长不重复子序列类似,似乎都可以利用滑窗法来解决(当然,此处的窗口大小必然是动态的,不固定的)。然而不同的是,S中的字符可能包含T中不存在的字符,也就是说:在滑窗构建的过程中(遍历S的过程中),会遇到两种情况,当前字符不是T中的字符和当前字符是T中的字符。那么如何构建滑窗呢?具体如下:

    (1)我们设置两个指针left和right,分别表示滑窗的两端。哈希表_map用于存储T中出现的字符以及相应的个数。cnt用于统计目前滑窗中出现的T中的字符的个数。

    (2)right指针不停的向右移动,并且判断此处的字符是否是T中的字符,是的话,计数器cnt加1,同时_map中相应的字符对应的次数减去1。当cnt的数值与T的长度相同时,表示我们已经构造完成了一个符合条件的滑窗了。

    (3)由于,整个S中可能存在多个符合条件的滑窗,所以当我们找到一个符合条件的滑窗时,需要记录相应的长度和起始下标;然后再去构建下一个滑窗。

    (4)如何构建下一个滑窗呢?此时,就需要操作左指针left了,将left向右移动,若left处的字符是T中的字符的话,则cnt减去1。相应的_map处的字符对应的次数加1,此时需要构建新的滑窗,再去操作right指针;重复这个过程直至遍历完S。如果left处的字符不是T中的字符的话,继续右移,知道遇到T中的字符。

    实现代码如下:

    class Solution {
    public:
        string minWindow(string S, string T) {
            int s_len = S.size();
            int t_len = T.size();
            if(s_len == 0 || t_len == 0 || s_len < t_len)//特殊输入的处理
                return "";
            int cnt = 0;//用于统计当前滑动窗口内中包含T中的字符的个数
            int len = INT_MAX;//此处我用的int的最小值,也可以用s_len + 1
            int head = -1;//记录最终结果的初始位置
            int left = 0, right = 0;//定义滑动窗口的两个边界
            unordered_map<char,int> _map;//存储T中的字符及出现的次数
            for(int i = 0; i < t_len; i++)//初始化哈希表_map
            {
                if(_map.find(T[i])  == _map.end())
                    _map.insert(pair<char,int>(T[i],1));
                else
                    (_map.find(T[i])->second)++;
            }
            for(right = 0 ; right < s_len; right++)//移动右指针
            {
                if(_map.find(S[right]) != _map.end())//当窗口内部含有T中的字符时
                {
                    _map[S[right]]--;//相应字符的此处减1
                    if(_map[S[right]] >= 0)//减1后如果次数大于等于0,说明我们已经满足一个字符了,所以cnt加1
                        cnt++;
                    while(cnt == t_len)//如果滑窗内已经包含所有T中的字符
                    {
                        if(right - left + 1 < len)//更新最小的情况
                        {
                            len = right - left + 1;
                            head = left;
                        }
                        if(_map.find(S[left]) != _map.end())//如果左指针处指的是T中的字符;如果不是T中的字符则继续左移
                        {
                            _map[S[left]]++;//相应处的字符的次数加1
                           if(_map[S[left]] > 0)//如果加1之后此处大于0了,说明需要这个字符(这个字符是唯一的),如果向右移动的话(舍去这个字符),cnt就会减1
                                cnt--;
                            //如果这个字符不是唯一的话,不需要操作
                        }
                        left++;//移动左指针,直到滑窗中不再包含T中的全部字符
                    }
                }
            }
            return head == - 1 ?"" : S.substr(head,len);//head== -1相当于没找到符合条件的子序列
    
        }
    };
    

      

    实际上,左指针移动时,相当于考虑了三种情况:left处的字符不是T中的字符、left处的字符是T中的字符且是唯一的、left处的字符是T中的字符但不是唯一的(滑窗中其他处还有这个字符,此时_map[S[left]]是小于等于0的)。

    我们也可以把_map[S[i]]理解成还需要多少个S[i]字符。该算法的时间复杂度为O(N),空间复杂度为O(1),因为ASCII码的话,最多256个字符就行。

  • 相关阅读:
    oracle基本语句
    java Scanner和异常
    流Stream 文件File 流IO
    java基本方法
    jsp页面展示更加商品的分类,控制商品的显示
    使用jquery select2实现下拉框搜索功能
    JSONObject和JSONArray
    GsonUtils.getGson().fromJson() 转泛型集合用法
    java 实现图片上传功能
    mysql :将其中两个数据的某一个字段合拼成一句
  • 原文地址:https://www.cnblogs.com/wangkundentisy/p/9330594.html
Copyright © 2011-2022 走看看