其他分享
首页 > 其他分享> > leetcode76.最小覆盖子串(困难)

leetcode76.最小覆盖子串(困难)

作者:互联网

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
双指针经典题目,可以看一下leetcode.209

自己的思路:
记录出s中每个字符后面该字符的位置,当left指针移动之后,导致窗口内少了一个字符,right直接移动到left之前指向的那个字符。
自己的思路存在的问题: 注意题目中t的字符是可重复的,如果不重复的话才可以这样做!
官方思路:
双指针。
难点:
1:如何判断right移动后的的窗口是否包含了t中所有的字符?
可以设置两个hash表(窗口内t中的字符搞一个, t搞一个),对这两个hash表逐个比较,如果存在一个字符,s_hash(该字符)<
t_hash(该字符) 则不满足
2:left right两个指针如何让移动?
right移动一直移动直到移动到可以满足的位置(窗口内元素个数>=t中的元素个数)之后。然后left一个一个进行移动,移动一次判断一次,并对ans更新。

class Solution {
public:
    unordered_map<char, int> s_hash, t_hash;
    bool enough();
    string minWindow(string s, string t) {
        //滑动窗口经典题目.
        //s_hash记录t中出现的字符的个数,t_hash记录t中字符的个数
        int n = s.size(), m = t.size();
        for (int i = 0; i < m; ++i) {
            t_hash[t[i]]++;
        }
        int left = 0, right = -1, ans_left, minlen = INT_MAX;
        while (right < n - 1) {
            right++;
            if (t_hash.find(s[right]) != t_hash.end()) {
                s_hash[s[right]]++;
            }
            if (enough()) {
                while (left < right && enough()) {
                    if (right - left + 1 < minlen) {
                        minlen = right - left + 1;
                        ans_left = left;
                    }
                    if (t_hash.find(s[left]) != t_hash.end()) {
                        s_hash[s[left]]--;
                    }
                    left++;
                }
                if (left == right && enough()) {
                    minlen = right - left + 1;
                    ans_left = left;
                }
            }
            
        }
        return minlen == INT_MAX ? "" : s.substr(ans_left, minlen);
    }
};
bool Solution::enough() {
    for (auto &m: t_hash) {
        if (s_hash[m.first] < m.second) return false;
    }
    return true;
}

改进:
上面的代码中,right移动的位置是0-n-1,可以缩小范围,把下标缩减([index1, index2],index1和index2指向的元素都是t中出现的元素)。

//改进如下:
class Solution {
public:
    unordered_map<char, int> s_hash, t_hash;
    bool enough();
    string minWindow(string s, string t) {

        int n = s.size(), m = t.size();
        int index1 = 0, index2 = n - 1; //下标范围
        for (int i = 0; i < m; ++i) {
            t_hash[t[i]]++;
        }
        while (index1 < n && t_hash.find(s[index1]) == t_hash.end()) index1++;  //index1移动
        while (index2 >= 0 && t_hash.find(s[index2]) == t_hash.end()) index2--; //index2移动
        int left = index1, right = index1 - 1, ans_left, minlen = INT_MAX;
        while (right < index2) { //right最多移动到index2的位置
            right++; 
            if (t_hash.find(s[right]) != t_hash.end()) {
                s_hash[s[right]]++;
            }
            if (enough()) {
                while (left < right && enough()) {
                    if (right - left + 1 < minlen) {
                        minlen = right - left + 1;
                        ans_left = left;
                    }
                    if (t_hash.find(s[left]) != t_hash.end()) {
                        s_hash[s[left]]--;
                    }
                    left++;
                }
                if (left == right && enough()) {
                    minlen = right - left + 1;
                    ans_left = left;
                }
            }
            
        }
        return minlen == INT_MAX ? "" : s.substr(ans_left, minlen);
    }
};
bool Solution::enough() {
    for (auto &m: t_hash) {
        if (s_hash[m.first] < m.second) return false;
    }
    return true;
}

标签:子串,right,hash,minlen,++,最小,enough,leetcode76,left
来源: https://blog.csdn.net/zhangjiaji111/article/details/120841564