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

題目列表

題目分析

滑動窗口,維護一個連續區間 [i,j)[i, j),右邊界不斷擴展,滿足一定條件時更新左邊界,直至遍歷整個數據。

滑動窗口的題目要明確何時更新右邊界,何時更新左邊界,可解決大部分求連續子串的問題。

Leetcode 3. 無重複字符的最長子串

給定一個字符串,請你找出其中不含有重複字符的 最長子串 的長度。

輸入: “abcabcbb”
輸出: 3
解釋: 因爲無重複字符的最長子串是 “abc”,所以其長度爲 3。

維護一個滑動窗口:
何時更新右邊界? 窗口內的字符不重複。
何時更新左邊界? 新進入的字符與窗口內的字符存在重複。

對於例題中的 abcabcbb,滑動窗口(窗口)左右邊界的座標初始爲0,然後右邊界不斷擴展,直到窗口內爲 abc 時滿足題目要求,右邊界繼續擴展,此時再進入 a,窗口變成了 abca,這時候不滿足要求。因此需要移動這個隊列的左邊界。左邊界只需要不斷彈出元素直到滿足窗口內字符不重複,比如壓入 a 時,窗口內 abc 以及包含了 a,只需要把窗口內 a 及之前的字符彈出即可。

優化:每次壓入都要遍歷一遍窗口判斷是否有相同字符,這樣最壞情況下的複雜度爲 O(n2)O(n^2) 。爲了進一優化目標,可以使用一個map,記錄在窗口的每個字符的位置,這樣在新進入字符時只需要訪問 map,即可判斷窗口內是否有該字符,並且有的話可以直接獲得該字符在窗口內的位置。每次進入字符時,更新窗口的最大大小,即可得到最長字串的長度。整個算法的時間複雜度變爲 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
發佈了18 篇原創文章 · 獲贊 2 · 訪問量 5191
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章