[Leetcode] [Tutorial] 滑动窗口


3. 无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。

Solution

使用两个指针,不是每次移动一位,而是直接跳到对应的位置。通过移动这两个指针形成新的窗口。

滑动窗口中使用字典来保存字符及其索引,当出现重复字符时,移动指向窗口的左侧的指针以去除重复字符。

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        left = 0
        max_len = 0
        dic = {
    
    }
        for right, char in enumerate(s):
            if s[right] in dic and dic[s[right]] >= left:
                left = dic[s[right]] + 1
            dic[s[right]] = right
            max_len = max(right - left + 1, max_len)
            right += 1
        return max_len

438. 找到字符串中所有字母异位词

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

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

示例:
输入: s = “cbaebabacd”, p = “abc”
输出: [0,6]

Solution

仅当窗口的大小等于字符串 p 的长度时,窗口内的子串才有可能是字符串 p 的异位词。换句话说,窗口的大小是固定的。

我们可以使用哈希表来记录窗口内的每个字符的数量,以便快速判断窗口内的字符串是否是 p 的异位词。

class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:
        p_counter = Counter(p)
        res = []

        for i in range(len(p) - 1, len(s)):
            s_counter = Counter(s[i - len(p) + 1: i + 1])
            if s_counter == p_counter:
                res.append(i - len(p) + 1)
        
        return res

需要注意的是,Python的切片操作不包括终止索引。

然而,这个算法的时间复杂度是O(n * m),其中n是字符串s的长度,m是字符串p的长度,因为对于s的每一个子串,我们都要计算它的字符计数。

如果只是在每次迭代时更新新的字符的计数,而不是重新计算整个窗口的字符的计数,也就是滑动窗口向右移动一步,新字符进入窗口,老字符离开窗口,只对新旧字符的计数进行增减,时间复杂度就可以从之前的 O(n*m) 降低到 O(n),其中 n 是字符串 s 的长度。这是因为对于 s 中的每一个字符,我们只执行常数时间的操作。

class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:
        p_counter = Counter(p)
        s_counter = Counter()
        res = []

        for i in range(len(s)):
            s_counter[s[i]] += 1

            if i >= len(p):
                s_counter[s[i - len(p)]] -= 1
            
            if s_counter == p_counter:
                res.append(i - len(p) + 1)

        return res

猜你喜欢

转载自blog.csdn.net/weixin_45427144/article/details/131312463