LeetCode76 最小覆盖子串

这篇博客介绍了如何使用滑动窗口和双指针策略解决LeetCode76问题。解题过程中,通过matchSuccess函数优化了官方的check方法,并讨论了时间复杂度为O(∣s∣+∣t∣),空间复杂度为O(C)的解决方案。还提到了使用一个哈希表来记录字符频数差值的方法。
摘要由CSDN通过智能技术生成

LeetCode76 最小覆盖子串

题目

在这里插入图片描述

解题:滑动窗口+双指针

解题思路见 最小覆盖子串,可以用 matchSuccess 来官方解答里的 check 函数,避免每次都要进行一一比较。

tFreq.size 后面不加括号。

// javascript
var minWindow = function(s, t) {
    const sFreq = new Map(), tFreq = new Map();
    // tFreq 记录 t 所有字符频数
    for (const tEle of t) {
       tFreq.set(tEle, (tFreq.get(tEle) || 0) + 1);
    }
    const sLen = s.length;
    let l = 0, r = 0, ansL = -1, distance = sLen + 1;
    let matchSuccess = 0;
    while (r < sLen) {
    	// 当前字符在 tFreq 的字符中,更新窗口统计
        if (tFreq.has(s[r]) === true) {
            sFreq.set(s[r], (sFreq.get(s[r]) || 0) + 1);
            if (sFreq.get(s[r]) === tFreq.get(s[r])) {
                matchSuccess += 1;
            }
        }
        // 直到 s 涵盖 t 所有字符 且 l <= r 时:开始收缩窗口
        while (matchSuccess === tFreq.size && l <= r) {
            // 更新最小 distance 和 起始位置 ansL
            if (r - l + 1 < distance) {
                distance = r - l + 1;
                ansL = l;
            }
            // 下一步要移除 l 所以如果 tFreq.has(s[l]) 是 true,sFreq 对应的字符频数要减少
            if (tFreq.has(s[l]) === true) {
                sFreq.set(s[l], sFreq.get(s[l]) - 1);
                if (sFreq.get(s[l]) < tFreq.get(s[l])) {
                    matchSuccess -= 1;
                }
            }
            // 移动窗口的左边界
            l++;
        }
        // 移动窗口的右边界
        r++;
    }
    return ansL === -1 ? "" : s.substr(ansL, distance);
};

时间复杂度:最坏情况下左右指针对 s s s 的每个元素各遍历一遍, t t t 的每个元素也会被遍历一遍, O ( ∣ s ∣ + ∣ t ∣ ) O(∣s∣+∣t∣) O(s+t)

空间复杂度:这里用了两张哈希表作为辅助空间,每张哈希表最多不会存放超过字符集大小的键值对,我们设字符集大小为 C C C ,则渐进空间复杂度为 O ( C ) O(C) O(C)

也可以 用一个哈希表,统计 t 中字符频数时 --,并且用此哈希表记录 s[left, right] 中在 t 中出现的字符的频数与 t 中的差值,如果等于 0 则说明某个字符的频数匹配上了。

// javascript
var minWindow = function(s, t) {
    const cnt = new Map();
    for (const tEle of t) cnt.set(tEle, (cnt.get(tEle) || 0) - 1);
    const sLen = s.length;
    let left = 0, ansL = -1, distance = sLen + 1;
    let matchSuccess = 0;
    for (let right = 0; right < sLen; right++) {
        if (cnt.has(s[right]) === true) {
            cnt.set(s[right], cnt.get(s[right]) + 1);
            if (cnt.get(s[right]) === 0) {
                matchSuccess += 1;
            }
        }
        while (matchSuccess === cnt.size && left <= right) {
            if (right - left + 1 < distance) {
                distance = right - left + 1;
                ansL = left;
            }
            if (cnt.has(s[left]) === true) {
                cnt.set(s[left], cnt.get(s[left]) - 1);
                if (cnt.get(s[left]) < 0) {
                    matchSuccess -= 1;
                }
            }
            left++;
        }
    }
    return ansL === -1 ? "" : s.substr(ansL, distance);
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值