leetcode刷題記錄:演算法(三)滑動視窗演算法
滑動視窗是為了減少迴圈次數。
滑動視窗有幾個應用場景:
- 給定一個整數陣列,計算長度為 ‘k’ 的連續子陣列的最大總和。
這中應用情況下,視窗大小是固定的,視窗每移動一步,視窗中的數值和上一步中的有重合,這個重合的部分不再參與計算,滑動視窗就是利用這個來將計算量減少。 - 給定一個字串S和一個目標字串T,找到S中包含所有T中字母的最小子字串。
這種情況下,視窗大小是變化的。先設定視窗大小為0,然後移動右側邊界,逐步擴張視窗,直至能滿足要求。
然後嘗試從左側減小視窗,如果不再滿足要求,就繼續從右側擴張視窗。
以此迴圈,可以得到最後的結果。
繼續刷題,還是飼養員up推薦的三道題。
3.無重複字元的最長子串
寫的有點複雜,搞了一個flag將情況分為移動左視窗和移動右視窗,還加了一個判斷特定情況的條件(是否是空字串)。
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
if len(s)==0:
return 0
s_left = 0
s_right = 0
max_len = 1
flag = 0 ##0時移動右視窗,1時移動左視窗
window = s[s_left]
while (s_right < len(s)-1):
if flag == 0:
s_right += 1
if s[s_right] not in window:
window = s[s_left:s_right+1]
if len(window) > max_len:
max_len = len(window)
elif s[s_right] in window:
flag = 1
window = s[s_left:s_right+1]
else:
s_left += 1
if s[s_left - 1] == s[s_right]:
flag = 0
window = s[s_left:s_right+1]
return max_len
官方給的答案如下,比我的答案短很多,但是執行起來時間和記憶體佔用比我的更拉胯。
其中,官方答案利用了一個雜湊集合,我一直用的列表切片。
可以學習到的幾點:
- 如何避免特殊情況,使得程式碼應用更廣泛(我自己寫的裡面對空字串和單字元的情況做了另外處理)
- 取最大值不要用if了,很蠢,python給提供了max函式竟然不用(嘆氣)
- 官方給的例子用了巢狀迴圈,減少了程式碼量,我則是通過flag來對右視窗進行多次移動的,即多次重複操作的時候,可以考慮用個迴圈代替flag。
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
# 雜湊集合,記錄每個字元是否出現過
occ = set()
n = len(s)
# 右指標,初始值為 -1,相當於我們在字串的左邊界的左側,還沒有開始移動
rk, ans = -1, 0
for i in range(n):
if i != 0:
# 左指標向右移動一格,移除一個字元
occ.remove(s[i - 1])
while rk + 1 < n and s[rk + 1] not in occ:
# 不斷地移動右指標
occ.add(s[rk + 1])
rk += 1
# 第 i 到 rk 個字元是一個極長的無重複字元子串
ans = max(ans, rk - i + 1)
return ans
209.長度最小的子陣列
好傢伙,我在上一個程式碼的基礎上修修補補,最後擊敗了全國百分之11的對手,垃圾製造者就是我了。
class Solution:
def minSubArrayLen(self, s: int, nums: List[int]) -> int:
# 這裡採用list了,不用set了,set的特性是沒有重複
occ = list()
ans = list()
n = len(nums)
if n == 0:
return 0
# 右指標,初始值為 -1,相當於我們在字串的左邊界的左側,還沒有開始移動
rk = -1
for i in range(n-1):
if i != 0:
# 左指標向右移動一格,移除一個字元
occ.pop(0)
while rk + 1 < n and sum(occ) < s:
# 不斷地移動右指標
occ.append(nums[rk + 1])
rk += 1
# 第 i 到 rk 個字元是一個極長的無重複字元子串
if sum(occ) >= s:
ans.append(rk - i + 1)
return 0 if len(ans)==0 else min(ans)
改了一遍,稍微好了一點,不過用for i in range(n)確實可以排除空集特殊情況:
class Solution:
def minSubArrayLen(self, s: int, nums: List[int]) -> int:
if len(nums) == 0:
return 0
s_left = 0
s_right = -1
sum_sub = 0
min_len = list()
flag = 0 ## 0時移動右視窗,1時移動左視窗
while (s_right < len(nums)):
if flag == 0 and s_right <len(nums)-1:
## 移動右視窗
s_right += 1
## 更新和
sum_sub += nums[s_right]
## 如果此時和不滿足要求,那麼flag不變,繼續移動右視窗
## 如果此時和滿足要求,那麼記錄長度,並開始移動左視窗
if sum_sub >= s:
min_len.append(s_right-s_left+1)
flag = 1
else:
## 移動左視窗
s_left += 1
## 更新和
sum_sub -= nums[s_left-1]
## 如果此時和不滿足要求,那麼停止移動左視窗,開始移動右視窗
if sum_sub < s:
flag = 0
## 如果此時和滿足要求,那麼記錄長度,並繼續移動左視窗
else:
min_len.append(s_right-s_left+1)
if s_left == s_right:
break
return 0 if len(min_len)==0 else min(min_len)
相關文章
- 滑動視窗演算法演算法
- 【演算法】滑動視窗三步走演算法
- 滑動視窗演算法思路演算法
- Sentinel滑動視窗演算法演算法
- 滑動視窗法——Leetcode例題LeetCode
- 力扣刷題-滑動視窗(字串)力扣字串
- leetcode刷題記錄:演算法(六)BFS&DFSLeetCode演算法
- 滑動視窗演算法(Sliding Window Algorithm)演算法Go
- 演算法題:返回滑動視窗中的最大值演算法
- 滑動視窗(Sliding Window)演算法介紹演算法
- 【演算法框架套路】滑動視窗演算法:匹配子串演算法框架
- LeetCode刷題記錄LeetCode
- 演算法~利用zset實現滑動視窗限流演算法
- 使用 Redis 實現限流——滑動視窗演算法Redis演算法
- 滑動視窗專題
- leetcode刷題記錄 661~LeetCode
- 「LeetCode Top100」之滑動視窗LeetCode
- leetcode排序專題演算法刷題LeetCode排序演算法
- [分散式限流] 滑動視窗演算法的 Golang 實現分散式演算法Golang
- 滑動視窗演算法基本原理與實踐演算法
- 《面試必備演算法》系列 滑動視窗入門面試演算法
- 7、滑動視窗套路演算法框架——Go語言版演算法框架Go
- LeetCode 239. 滑動視窗最大值LeetCode
- hot100-一刷-03滑動視窗(共2道題)
- 每週刷個 leetcode 演算法題LeetCode演算法
- 滑動視窗問題總結
- LeetCode刷題記錄——day5LeetCode
- LeetCode刷題記錄——day4LeetCode
- LeetCode刷題記錄——day3LeetCode
- LeetCode刷題記錄——day2LeetCode
- LeetCode刷題記錄——day1LeetCode
- LeetCode解題記錄(貪心演算法)(二)LeetCode演算法
- LeetCode解題記錄(貪心演算法)(一)LeetCode演算法
- Sentinel-Go 原始碼系列(三)滑動時間視窗演算法的工程實現Go原始碼演算法
- 演算法刷題:LeetCode中常見的動態規劃題目演算法LeetCode動態規劃
- vscode的LeetCode演算法刷題外掛VSCodeLeetCode演算法
- 有點難度,幾道和「滑動視窗」有關的演算法面試題演算法面試題
- 【完虐演算法系列】「字串 – 滑動視窗」覆盤總結演算法字串