筆試面試——滑動窗口

推薦閱讀算法思維繫列/滑動窗口技巧.

子串問題

LC76. Minimum Window Substring

題目鏈接:Minimum Window Substring

在這裏插入圖片描述

from collections import defaultdict

class Solution:
    def minWindow(self, s: str, t: str):
        left, right = 0, 0
        window = defaultdict(int)
        
        # “給出2字符串S和T,求S中包含T的所有字母的某些子串”需要的變量
        needs = defaultdict(int)
        match = 0  # window匹配了多少種needs中的字符
        for c in t:  # 初始化needs
            needs[c] += 1
            
        # 本題需要的記錄返回值的變量
        start, min_len = 0, float('inf')
        
        
        while right < len(s):
        
            c1 = s[right]  # 右移right的同時需要維護window和match(5行)
            if c1 in needs:  
                window[c1] += 1
                if window[c1] == needs[c1]:  # 注意這裏是=而不是≥,因爲只需要在相等時記錄該字符的次數已經足夠,如果後面還有該字符,也不能加大match,所以對某個字符來說只會加一次match
                    match += 1 
            
            while match == len(needs):  # 每右移一步就檢查是否滿足題意的充分條件(match==len(needs)說明所有字母都已出現,但是字母出現次數大於等於需要的次數),符合則將left右移多步直到不滿足
            
                if right - left + 1 < min_len:  # 檢查是否滿足題意的必要條件(找到符合條件的最短子串)
                    start = left
                    min_len = right - left + 1
                    
                c2 = s[left]  # 右移left的同時需要維護window和match(5行)
                if c2 in needs:  
                    window[c2] -= 1
                    if window[c2] < needs[c2]:  # 注意這裏是<,當≥時都只減去window[c2],不見match,直到減完後小於needs[c2],這時減match,而下輪循環就會跳出(match != len(needs))。所以整個循環只會減一次match
                        match -= 1
                left += 1  # 內層循環的末尾將left右移
            right += 1  # 外層循環的末尾將right右移
            
        return s[start:start + min_len] if min_len < float('inf') else ''

LC438. Find All Anagrams in a String

題目鏈接:Find All Anagrams in a String

在這裏插入圖片描述

from collections import defaultdict

class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:
        left,right=0,0
        window=defaultdict(int)
        
        # “給出2字符串S和T,求S中包含T的所有字母的某些子串”需要的變量
        needs=defaultdict(int)
        match=0
        for c in p:  # 初始化needs
            needs[c]+=1
        
        # 本題需要的記錄返回值的變量
        res=[]
            
        while right<len(s):
        
            c1=s[right]  # 右移right的同時需要維護window和match(6行,前5行是爲了right+=1)
            if c1 in needs:  
                window[c1]+=1
                if window[c1]==needs[c1]:
                    match+=1
            right+=1
            
            while match==len(needs):  # 每右移一步就檢查是否滿足題意的充分條件(match==len(needs)說明所有字母都已出現,但是字母出現次數大於等於需要的次數),符合則將left右移多步直到不滿足
            
                if right-left+1==len(p):  # 檢查是否滿足題意的必要條件(子串長度恰好等於模板長度),是則更新返回值
                    res.append(left)
                
                c2=s[left]  # 右移left的同時需要維護window和match(6行,前5行是爲了left+=1)
                if c2 in needs:  
                    window[c2]-=1
                    if window[c2]<needs[c2]:
                        match-=1
                left+=1 
            
        return res

LC3. Longest Substring Without Repeating Characters

題目鏈接:Longest Substring Without Repeating Characters

在這裏插入圖片描述
PS:注意本題的window存放字符次數的含義與上面兩題不同,前面兩題window存放的是窗口left到right(包含)子串中出現了needs中的字符以及次數,而本題沒有needs,window記錄的是窗口中所有字符的次數

from collections import defaultdict

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        left,right=0,0
        window=defaultdict(int)
        
        # 本題需要的記錄返回值的變量
        res=0
        
        while right<len(s):
        
            c1=s[right]  # 右移right的同時需要維護window(3行,前2行是爲了right+=1)
            window[c1]+=1  
            right+=1
            
            while window[c1]>1:  # 每右移一步就檢查是否滿足題意的“充分”條件(子串含有重複字符),符合則將left右移多步直到不滿足
            
                c2=s[left]  # 右移left的同時需要維護window(3行,前2行是爲了left+=1)
                window[c2]-=1  
                left+=1
                
            # 只有結束了內層循環才滿足必要條件(子串無重複字符),此時檢查是否需要更新返回值
            res=max(res,right-left+1)
            
        return res

劍指offer:和爲S的連續正數序列

題目鏈接:https://www.nowcoder.com/practice/c451a3fd84b64cb19485dad758a55ebe

在這裏插入圖片描述

參考答案:

# -*- coding:utf-8 -*-
class Solution:
    def FindContinuousSequence(self, tsum):
        # https: // www.nowcoder.com / questionTerminal / c451a3fd84b64cb19485dad758a55ebe?f = discussion
        result = []
        # 兩個起點,相當於動態窗口的兩邊,根據其窗口內的值的和來確定窗口的位置和大小
        low, high = 1, 2
        while low < high:
            # 由於是連續的,差爲1的一個序列,那麼求和公式是(a0+an) * n / 2
            cur = (high + low) * (high - low + 1) / 2
            # 相等,那麼就將窗口範圍的所有數添加進結果集
            if cur == tsum:
                result.append([i for i in range(low, high + 1)])
                low += 1
            #  如果當前窗口內的值之和小於sum,那麼右邊窗口右移一下
            elif cur < tsum:
                high += 1
            else:
                # 如果當前窗口內的值之和大於sum,那麼左邊窗口右移一下
                low += 1
        return result

其他

劍指offer:遞增數組中和爲S的兩個數字

題目鏈接:https://www.nowcoder.com/practice/390da4f7a00f44bea7c2f3d19491311b

在這裏插入圖片描述
解題思路:
在這裏插入圖片描述

參考答案:

# -*- coding:utf-8 -*-
class Solution:
    def FindNumbersWithSum(self, arr, tsum):
       # 鏈接:https://www.nowcoder.com/questionTerminal/390da4f7a00f44bea7c2f3d19491311b?f=discussion
        n = len(arr)
        i, j = 0, n - 1
        while i < j:
            cur = arr[i] + arr[j]
            if cur == tsum:
                return [arr[i],arr[j]]
            elif cur > tsum:
                j-=1
            else:
                i+=1
        return []
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章