二十天刷题计划--滑动窗口(1)

127 阅读2分钟

「这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战」。

1.题目

盛最多水的容器

给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

示例 1:

输入: s = "cbaebabacd", p = "abc" 输出: [0,6] 解释: 起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。 起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。

 示例 2:

输入: s = "abab", p = "ab" 输出: [0,1,2] 解释: 起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。 起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。 起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。  

提示:

1 <= s.length, p.length <= 3 * 104 s 和 p 仅包含小写字母


思路

具体的,我们可以先创建一个大小为 2626 的数组 c2c2 来统计字符串 p 的词频,另外一个同等大小的数组 c1c1 用来统计「滑动窗口」内的 s 的子串词频。

当两个数组所统计词频相等,说明找到了一个异位组,将窗口的左端点加入答案。

时间复杂度: 令 s 和 p 的长度分别为 nn 和 mm,C = 26C=26 为字符集大小。 统计 p 词频(构建 c2c2 数组)的复杂度为 O(m)O(m);使用双指针检查 s 串的复杂度为 O(C * n)O(C∗n)。 整体复杂度为 O(C*n + m)O(C∗n+m) 空间复杂度:O(C)O(C)


代码

var findAnagrams = function(s, p) {
    let tar = new Map();
    
    function findRes(map) {
        let values = map.values();
        for (let v of values) {
            if (v !== 0) return false;
        }
        return true;
    }

    for (let i of p) {
        if (tar.has(i)) tar.set(i, tar.get(i)+1);
        else tar.set(i, 1);
    }

    let l = 0; r = 0;
    let res = [];
    while (r < s.length+1) {
        if (r < p.length) {
            if (tar.has(s[r])) tar.set(s[r], tar.get(s[r])-1);
            r++;
        } else {
            if (findRes(tar)) res.push(l);
            if (tar.has(s[l])) tar.set(s[l], tar.get(s[l])+1);
            if (r < s.length && tar.has(s[r])) tar.set(s[r], tar.get(s[r])-1);
            l++; r++;
        }
    }

    return res;
};