python3實現最小覆蓋子串——滑動窗口算法


題目

給定一個字符串 S、一個字符串 T,請在字符串 S 里面找出:包含 T 所有字母的最小子串。

示例:

輸入: S = "ADOBECODEBANC", T = "ABC"
輸出: "BANC"

說明:

  • 如果 S 中不存這樣的子串,則返回空字符串 ""。
  • 如果 S 中存在這樣的子串,我們保證它是唯一的答案。

提示:根據LeetCode的官方解答,字符串T中可能有重復的字符,所以我們的答案需要保證字符類型和數量都一致。例如:T=“aabc”,則最小字串可能為“baac”,而不是“bac”

所以可以從字符串T中字母的出現的類型和頻率入手,兩者都要統計。可以通過python的字典類型來記錄。

題目來源

滑動窗口算法

滑動窗口算法可以用以解決數組/字符串的子元素問題,它可以將嵌套的循環問題,轉換為單循環問題,降低時間復雜度。

窗口可以是固定大小,起始和終止位置同時變化。

也可以是可變大小,起始和終止位置不同時變化。

參考鏈接

思路

  1. 利用滑動窗口,從第一個字符開始,逐漸向右查找,當字符出現的類型和頻率均滿足要求,則找到了一個符合條件的字串。但這個字串可能不是最小字串。
  2. 接着保持滑動窗口右邊界不變,收縮左邊界,觀察長度減小后字串是否依然滿足條件,如果滿足,則繼續收縮左邊界,直到不能收縮為止。
  3. 如果這個字串長度小於之前找到的字串長度,則更新結果。
  4. 保持滑動窗口左邊界不動(實際上左邊界應該往右挪一個),擴張右邊界,繼續找符合條件的字串。然后通過步驟2,3找到滿足條件的最小字串,直到遍歷整個字符串S。

python3實現

def minWindow(s: str, t: str) -> str:
    left = 0
    minlen = len(s)+1
    i = 1  # 指針
    result = ""
    char_t = dict()  # 字典,用於統計t中不同字符出現的個數
    char_win = dict()  # 字典,用於統計滑動窗口中不同字符的個數
    count = 0  # 用於統計滑動窗口中有多少字符滿足數量需求
    FORM = 0  # 記錄t中不同字符的格個數,count與form相等時滿足條件
    if not s or not t:  # 空串
        return result
    for i in t:
        #遇到新的字符則加入
        if not (i in char_t):
            char_t[i]=1
            char_win[i]=0
            FORM+=1
        else:
            char_t[i]+=1

    for i in range(len(s)):
        letter=s[i]
        if letter in char_t:
            char_win[letter]+=1
            if char_win[letter]==char_t[letter]:
                count+=1
        if count==FORM:#找到滿足條件的字串
            # 收縮左邊框
            if i!=len(s):#滑動窗口未擴張到最后一個字符
                while(True):
                    #字符不在t中出現
                    if(s[left] not in t):
                        left += 1
                    #字符在t中出現
                    else:
                        temp_len=len(s[left:i+1])
                        if (char_win[s[left]]>char_t[s[left]])and(temp_len>len(t)):
                            char_win[s[left]]-=1
                            left+=1
                        else:
                            break
                #更新minlen和result
                temp=s[left:i+1]
                if len(temp)<minlen:
                    minlen=len(temp)
                    result=temp
            else:
                while(True):
                    #字符不在t中出現
                    if(s[left] not in t):
                        left += 1
                    #字符在t中出現
                    else:
                        temp_len=len(s[left:])
                        if (char_win[s[left]]>char_t[s[left]])and(temp_len>len(t)):
                            char_win[s[left]]-=1
                            left+=1
                        else:
                            break
                #更新minlen和result
                temp=s[left:]
                if len(temp)<minlen:
                    minlen=len(temp)
                    result=temp
        
            char_win[s[left]]-=1
            count-=1
            left+=1
    return result


S = "ADOBECODEBANC"
T = "ABC"
print("答案:"+minWindow(S, T))

S2 = "abbbbbbbbabc"
T2 = "abc"
print("答案2:"+minWindow(S2, T2))

做題心得:

這個題的困難之處在於如何判斷字串滿足條件。一開始注意力都集中在字符的類型相同上,數量只是附帶檢驗。但實際上可以巧妙利用字符出現的頻率(數量)來作為判斷條件。

其次滑動窗口擴張到最后一個字符的時候要單獨判斷,因為python的字符串切片[begin:end]截取的字符串下標是從begin到end-1,如果i移動到字符串末尾,i+1會越界


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM