12 哈希+不定长滑窗:最小覆盖子串 76

目录

    最小覆盖子串
    又是一道硬题。
    咱今天先把题干给读懂。
    image

    不定长滑窗
    ADOBEC
    DOBECODEBA
    OBECDEBA
    BECDEBA
    ECDEBA
    CDEBA
    DEBANC
    EBANC
    BANC
    ANC

    我的思路是。
    双指针,右指针不断向右滑动。
    Q1.左指针什么时候动?
    当右指针发现子串已经覆盖ABC(具体如何实现呢)时,左指针向右滑动,直到不能覆盖子串。
    Q2.说得简单,如何知道子串有没有覆盖ABC呢?
    可以把数组当做哈希表,26个字母对应26个下标,碰到了哪个字符就让哪个字符+1。
    难道说右指针每次移动都要遍历一遍这个哈希表,看看是否满足条件吗?
    这样时间复杂度是O(n^2)啊。

    脑子崩了。

    今天已经是6月1日了,又试着写了写,写不出来。
    上题解!

    点击查看代码
    class Solution {
        bool is_covered(int cnt_s[], int cnt_t[]) {
            for (int i = 'A'; i <= 'Z'; ++i) {
                if (cnt_s[i] < cnt_t[i])
                    return false;
            }
            for (int i = 'a'; i <= 'z'; ++i) {
                if (cnt_s[i] < cnt_t[i])
                    return false;
            }
            return true;
        }
    public:
        string minWindow(string s, string t) {
            int cnt_s[128]{};
            int cnt_t[128]{};
            bool flag = false;
            int len = INT_MAX, start = 0;
            int left = 0;
            for (auto& ch : t) {
                ++cnt_t[ch];
            }
            for (int i = 0; i < s.length(); ++i) {
                // 元素进入窗口
                ++cnt_s[s[i]];
                if (i < t.length() - 1)
                    continue;
                while (is_covered(cnt_s, cnt_t)) {
                    if (len > i - left + 1) {
                        len = i - left + 1;
                        start = left;
                    }
                    --cnt_s[s[left]];
                    ++left;
                }
            }
            if (len == INT_MAX)
                return "";
            return s.substr(start, len);
        }
    };
    
    

    碎碎念。

    总算通过了。
    我刚开始的思路是正确的。
    就是两个哈希表分别记录这两个字符串的元素,然后对于主串就是滑动窗口,计数。
    然后我没写出来主要是因为两点。

    • 我最开始用的是数组array,是因为之前做过一道题array可以直接用==比较,但是又看题发现主串元素只要覆盖子串即可,所以>=也是可以的,那我就在想,这我该如何实现呢?
      天哪,我都没想过自己写一个函数,比较a-z,A-Z就可以了,就是这样简单。
    • 还有一点我在用数组的时候,我没想过是直接用char,我最开始用的是char-'a'。脑子瓦特了,一时间不知道A和a的ASCII码值谁大。
      这下记住了A是小的。
      可问题又出现了,char-A还能出现负数!
      那我想的只有一种结果,那就是while循环因为并没有判断它和i的关系,所以left指向\0了……
      所以最后我就直接用char了。
      OK,题解明天再仔细看吧,要去吃饭了,再见!

    2025-06-02 08:38:16 星期一
    崭新的一天!

    再来回顾一下这个最小覆盖子串的解法。

    哈希表+不定长滑窗。
    一个哈希表用来记录子串的字符,另一个哈希表记录遍历中的主串。
    元素进入窗口,又指针右移;直到哈希表中的字符数大于等于子串哈希表字符数,开始检查主串能否覆盖子串。

    Q1:覆盖如何判断?

    若覆盖,则记录子串长度和子串的起点位置;
    否则,剔除左指针所指元素,左指针右移。
    时间复杂度:子串遍历O(m)+主串左指针和右指针至多移动O(n),每次循环还要比对两个哈希表是否相等O(26+26)
    好像是O(m+52n)
    空间复杂度:主要是两个哈希表,但也是O(1),因为数组长度不因那个字符串长度增长。

    现在看题解,我们的思路和题解第一种方法是差不多的。
    下面就是如何继续优化?

    天哪,没心情看了,标记一下吧。

    posted @ 2025-05-29 10:58  王仲康  阅读(22)  评论(0)    收藏  举报