題目
給定一個字符串 S、一個字符串 T,請在字符串 S 里面找出:包含 T 所有字母的最小子串。
示例:
輸入: S = "ADOBECODEBANC", T = "ABC"
輸出: "BANC"
說明:
- 如果 S 中不存這樣的子串,則返回空字符串 ""。
- 如果 S 中存在這樣的子串,我們保證它是唯一的答案。
提示:根據LeetCode的官方解答,字符串T中可能有重復的字符,所以我們的答案需要保證字符類型和數量都一致。例如:T=“aabc”,則最小字串可能為“baac”,而不是“bac”
所以可以從字符串T中字母的出現的類型和頻率入手,兩者都要統計。可以通過python的字典類型來記錄。
滑動窗口算法
滑動窗口算法可以用以解決數組/字符串的子元素問題,它可以將嵌套的循環問題,轉換為單循環問題,降低時間復雜度。
窗口可以是固定大小,起始和終止位置同時變化。
也可以是可變大小,起始和終止位置不同時變化。
思路
- 利用滑動窗口,從第一個字符開始,逐漸向右查找,當字符出現的類型和頻率均滿足要求,則找到了一個符合條件的字串。但這個字串可能不是最小字串。
- 接着保持滑動窗口右邊界不變,收縮左邊界,觀察長度減小后字串是否依然滿足條件,如果滿足,則繼續收縮左邊界,直到不能收縮為止。
- 如果這個字串長度小於之前找到的字串長度,則更新結果。
- 保持滑動窗口左邊界不動(實際上左邊界應該往右挪一個),擴張右邊界,繼續找符合條件的字串。然后通過步驟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會越界