滑动窗口 Leetcode 3,30,76,438,567,632

题目列表

题目分析

滑动窗口,维护一个连续区间 [ i , j ) [i, j) [i,j),右边界不断扩展,满足一定条件时更新左边界,直至遍历整个数据。

滑动窗口的题目要明确何时更新右边界,何时更新左边界,可解决大部分求连续子串的问题。

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

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

输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。

维护一个滑动窗口:
何时更新右边界? 窗口内的字符不重复。
何时更新左边界? 新进入的字符与窗口内的字符存在重复。

对于例题中的 abcabcbb,滑动窗口(窗口)左右边界的坐标初始为0,然后右边界不断扩展,直到窗口内为 abc 时满足题目要求,右边界继续扩展,此时再进入 a,窗口变成了 abca,这时候不满足要求。因此需要移动这个队列的左边界。左边界只需要不断弹出元素直到满足窗口内字符不重复,比如压入 a 时,窗口内 abc 以及包含了 a,只需要把窗口内 a 及之前的字符弹出即可。

优化:每次压入都要遍历一遍窗口判断是否有相同字符,这样最坏情况下的复杂度为 O ( n 2 ) O(n^2) O(n2) 。为了进一优化目标,可以使用一个map,记录在窗口的每个字符的位置,这样在新进入字符时只需要访问 map,即可判断窗口内是否有该字符,并且有的话可以直接获得该字符在窗口内的位置。每次进入字符时,更新窗口的最大大小,即可得到最长字串的长度。整个算法的时间复杂度变为 O ( n ) O(n) O(n)

Leetcode 76. 最小覆盖字串

给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串。

输入: S = “ADOBECODEBANC”, T = “ABC”
输出: “BANC”

仍然是滑动窗口:
何时更新右边界? 窗口内的字符没有包含所有的T中的字符。
何时更新左边界? 窗口内已经包含了所有T中的字符。

滑动窗口首先不断扩展右边界,直到寻找到一个可行的子串包含T中的所有字母,然后更新左边界,不断收缩窗口来寻得满足条件的最短窗口大小。当更新左边界后窗口无法包含所有T中的字母时,再更新右边界,依次循环求解。

优化: 使用一个map记录T中每个字符需要的个数,然后更新右边界时,新进入的字符s如果是T中的字符,那么map[s]–;更新左边界时,新弹出的字符s如果是T中的字符,那么map[s]++;如果map中所有的value之和小于等于0,说明窗口内已经满足包含T中的所有字符,否则没有包含。

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

给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。

字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。

说明:

  • 字母异位词指字母相同,但排列不同的字符串。
  • 不考虑答案输出的顺序。

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

固定长度的滑动窗口。
何时更新右边界? 窗口小于p的长度。
何时更新左边界? 新进入的字符不在p中或者窗口等于p的长度。

Note:使用一个map记录p中所需字符及其个数,再使用一个map记录窗口内的字符及其个数,两者相等时即满足条件。

题目代码

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

class Solution(object):
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        start = 0
        maxcount = 0
        mapV = {}
        # 右边界扩展
        for i in range(len(s)):
        	# 是否更新左边界
            start = max(start, mapV.get(s[i], -1))
            # 更新新进入的字符的坐标
            mapV[s[i]] = i + 1
            # 更新窗口最大的大小
            maxcount = max(maxcount, i - start + 1)
        return maxcount

Leetcode 30. 串联所有单词的子串

class Solution(object):
    def findSubstring(self, s, words):
        """
        :type s: str
        :type words: List[str]
        :rtype: List[int]
        """
        if len(words)==0:
            return []
        record = {}
        for word in words:
            record[word] = record.get(word, 0) + 1
        winRecord = {}
        start = end = 0
        ans = []
        length = len(words[0])
        while(end<len(s)-length+1):
            word = s[end:end+length]
            if word in record.keys():
                end += length
                winRecord[word] = winRecord.get(word, 0) + 1
                if end - start == len(words)*length:
                    if winRecord==record:
                        ans.append(start)
                    start = end = start + 1
                    winRecord.clear()
            else:
                winRecord.clear()
                start = end = start + 1
        return ans

Leetcode 76. 最小覆盖字串

class Solution(object):
    def minWindow(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: str
        """
        tCount = dict()
        for w in t:
            tCount[w] = tCount.get(w, 0) + 1
        start = 0
        minStr = s + "0"
        NotAllIn = any(map(lambda x: x > 0, tCount.values()))
        for i in range(len(s)):
            if s[i] in tCount.keys():
                tCount[s[i]]-=1
            NotAllIn = any(map(lambda x: x > 0, tCount.values()))
            while not NotAllIn:
                if i-start+1 < len(minStr):
                    minStr = s[start:i+1]
                if s[start] in tCount.keys():
                    tCount[s[start]] += 1
                NotAllIn = any(map(lambda x: x > 0, tCount.values()))
                start = start + 1
        return "" if len(minStr) > len(s) else minStr

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

class Solution(object):
    def findAnagrams(self, s, p):
        """
        :type s: str
        :type p: str
        :rtype: List[int]
        """
        words = {}
        for w in p:
            words[w] = words.get(w, 0) + 1
        winwords = {}
        ans = []
        start = -1
        for i in range(len(s)):
            if s[i] in words.keys():
                if start == -1:
                    start = i
                winwords[s[i]] = winwords.get(s[i], 0) + 1
                if i-start+1==len(p):
                    if winwords == words:
                        ans.append(start)
                    winwords[s[start]] -= 1
                    start += 1

            else:
                start = -1
                winwords.clear()
        return ans
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值