76. 最小覆盖子串(滑动窗口)

O(1)的字符频度匹配

设计一个 distance数组记录 s字串和 t的匹配程度。也就是每个字符频度的差 s[c] - t[c] = distance[c]

t初始化distance中个字符的频度,如果s[c] 统计到一个,就在distance--,这样,当distance为0时,就代表这个字符完全匹配。
此外再创建一个count记录有几个字符频度完全匹配。初始化是t中不匹配的字符数,当一个字符频度完全匹配时,就count--。
这样,当每次count为0时,就表示完全匹配

更新:右边界移动时,尝试distance、count--
左边界移动时,尝试++


正确性

本质是暴力匹配的优化

对于本题有如下规律
向上单调合法,如果一个串合法[left,right],则[left,right'] (right'>right)也合法
向下单调不合法,如果一个串不合法[left,right],则[left',right] (left'>left) 也不合法

left开始向右穷举,假设 right 匹配到合法的边界[left1,right1],由于向上单调合法,同时寻找的是最小匹配,则right无需向后遍历。穷举下一个left。此时最大不合法区间为[left1,right-1]
设下一个循环中的右边界为right',由于向下单调不合法,[left1+1,right'] (right'<= right-1) 一定不合法 ,所以可以直接在上次循环的基础上继续right向后遍历,直到遇到合法区间

所以正确性与暴力匹配相同

class Solution {
public:
    string minWindow(string s, string t) {
        int m = s.length();
        int ans_left = -1, ans_right = m;
        int distance[128]{}; // 记录 s 和 t 的匹配程度
        int count = 0; // 记录有几个字符频度完全匹配

        // 初始化 distance 和 count
        for (char c : t) {
            if (distance[c] == 0) {
                count++; // t 中不匹配的字符数
            }
            distance[c]++;
        }

        int left = 0;
        for (int right = 0; right < m; right++) { // 移动子串右端点
            char c = s[right]; // 右端点字母
            distance[c]--; // 右端点字母移入子串
            if (distance[c] == 0) {
                // 一个字符频度完全匹配
                count--;
            }
            while (count == 0) { // 完全匹配
                if (right - left < ans_right - ans_left) { // 找到更短的子串
                    ans_left = left; // 记录此时的左右端点
                    ans_right = right;
                }
                char x = s[left]; // 左端点字母
                if (distance[x] == 0) {
                    // x 移出窗口之前,检查出现次数
                    // 如果窗口内 x 的出现次数和 t 一样
                    // 那么 x 移出窗口后,窗口内 x 的出现次数比 t 的少
                    count++;
                }
                distance[x]++; // 左端点字母移出子串
                left++;
            }
        }
        return ans_left < 0 ? "" : s.substr(ans_left, ans_right - ans_left + 1);
    }
};

参考了灵神的代码实现 https://leetcode.cn/problems/sliding-window-maximum/solutions/2499715/shi-pin-yi-ge-shi-pin-miao-dong-dan-diao-ezj6

posted @ 2025-03-25 21:30  丘狸尾  阅读(10)  评论(0)    收藏  举报