lintcode 32 最小子串覆盖

描述

给定一个字符串source和一个目标字符串target,在字符串source找到包括所有目标字符串字母的子串。

如果在source没有这样的子串,返回"",如果有多个这样的子串,返回起始位置最小的子串。

说明

在答案的子串中的字母在目标字符串中是否需要具有相同的顺序?

——不需要。

样例

给出source = "ADOBECODEBANC"target = "ABC" 满足要求的解  "BANC"

挑战

要求时间复杂度为O(n)

解题思路: 
总体思想就是先扫描一遍找到最后一个元素满足t字符串的,然后从左边向右开始收缩,使得满足t字符串的最少字符串返回。 
这题先用Map统计t中每个字符和每个字符出现的次数,key表示字符,value表示字符出现的次数。设置一个变量count,然后去从左到右扫描s字符串,如果s中的字符与Map中的字符相等的话,则Map中的字符的次数减去1,并且 count加1

如果count值等于t字符串的长度,然后用end-begin+1的长度与给定的lenth相比较,如果end-begin+1小于lenth,则len=end-begin+1

然后再用s字符串中的left的元素与map比较(即之前比较过的元素,这一步是为了一个个恢复之前比较过的元素的value值,在right后寻找)

然后将子窗口的左边界向右移,略掉不在T中的字符,如果某个在T中的字符出现的次数大于哈希表中的value,则也可以跳过该字符。

举例:ADOBEC比较过了,去掉A比较DOBECODEBA->BECODEBA->ECODEBA->CODEBA->ODEBANC->.......->BANC


代码如下

class Solution {
public:
    string minWindow(string S, string T) {
        if (T.size() > S.size()) return "";
        string res = "";
        int left = 0, count = 0, minLen = S.size() + 1;
        unordered_map<char, int> m;
        for (int i = 0; i < T.size(); ++i) {
            if (m.find(T[i]) != m.end()) ++m[T[i]];//保证当s中某一字符出现的次数大于t中时,只计算第一个,后面相同的都跳过
            else m[T[i]] = 1;
        }
        for (int right = 0; right < S.size(); ++right) {
            if (m.find(S[right]) != m.end()) {
                --m[S[right]];
                if (m[S[right]] >= 0) ++count;
                while (count == T.size()) {
                    if (right - left + 1 < minLen) {
                        minLen = right - left + 1;
                        res = S.substr(left, minLen);
                    }
                    if (m.find(S[left]) != m.end()) {
                        ++m[S[left]];
                        if (m[S[left]] > 0) ????        --count;
                    }
                    ++left;
                }
            }
        }
        return res;
    }
};

猜你喜欢

转载自blog.csdn.net/weixin_41413441/article/details/81034743