赞
踩
滑动窗口的动态演示:
【力扣209题】
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。
示例:
输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。
滑动窗口演示图
演示题解代码:
def minSubArrayLen(s: int, nums: List[int]) -> int: summation = 0 L, R = 0, -1 optim = len(nums) + 1 while R < len(nums): while R < len(nums): R += 1 if R < len(nums): summation += nums[R] if summation >= s: optim = min(optim, R - L + 1) break if R == len(nums): break while L < R: summation -= nums[L] L += 1 if summation >= s: optim = min(optim, R - L + 1) else: break return optim if optim != len(nums) + 1 else 0
力扣第3题:
无重复字符的最长子串
上题的模板可以总结为:
初始化窗口端点L,R,一般L为0,R为1 初始化最优值 while R < len(Array): while R < len(Array): R += 1 #移动右端点 if R < len(Array): 更新状态 if 状态满足条件: 可选的更新最优值的位置 break #一旦满足条件即跳出 if R == len(Array): # 若循环是由于移动到数组末尾结束,则停止整个程序。因为之后已经不再有可能的解 break while L < R: 更新状态 # 移动左端点,需要更新状态 L += 1 if 状态满足条件: 可选的更新最优值的位置 else: # 一旦窗口所在区间不再满足条件即跳出,去移动右端点 break 可选的对于L,R端点的后续处理 return 最优值
用以上模板可以写出相应的题解(无重复元素的最长子串):
def lengthOfLongestSubstring(s: str) -> int: L, R = 0, -1 optim = 0 status = set() while R < len(s): while R < len(s): R += 1 if R == len(s): break if s[R] not in status: status.add(s[R]) optim = max(optim, R - L + 1) else: break if R == len(s): break while L < R: if s[L] != s[R]: status.remove(s[L]) L += 1 else: L += 1 break return optim
茴香豆的四种写法:
力扣3题的另外相关模板集合:
模板1:使用defaultdict
class Solution: def lengthOfLongestSubstring(self, s): """ :type s: str :rtype: int """ from collections import defaultdict lookup = defaultdict(int) start = 0 end = 0 max_len = 0 counter = 0 while end < len(s): if lookup[s[end]] > 0: counter += 1 lookup[s[end]] += 1 end += 1 while counter > 0: if lookup[s[start]] > 1: counter -= 1 lookup[s[start]] -= 1 start += 1 max_len = max(max_len, end - start) return max_len
class Solution: def lengthOfLongestSubstring(self, s: str) -> int: # Step 1: 定义需要维护的变量, 本题求最大长度,所以需要定义max_len, 该题又涉及去重,因此还需要一个哈希表 max_len, hashmap = 0, {} # Step 2: 定义窗口的首尾端 (start, end), 然后滑动窗口 start = 0 for end in range(len(s)): # Step 3 # 更新需要维护的变量 (max_len, hashmap) # i.e. 把窗口末端元素加入哈希表,使其频率加1,并且更新最大长度 hashmap[s[end]] = hashmap.get(s[end], 0) + 1 if len(hashmap) == end - start + 1: max_len = max(max_len, end - start + 1) # Step 4: # 根据题意, 题目的窗口长度可变: 这个时候一般涉及到窗口是否合法的问题 # 这时要用一个while去不断移动窗口左指针, 从而剔除非法元素直到窗口再次合法 # 当窗口长度大于哈希表长度时候 (说明存在重复元素),窗口不合法 # 所以需要不断移动窗口左指针直到窗口再次合法, 同时提前更新需要维护的变量 (hashmap) while end - start + 1 > len(hashmap): head = s[start] hashmap[head] -= 1 if hashmap[head] == 0: del hashmap[head] start += 1 # Step 5: 返回答案 (最大长度) return max_len
力扣1004. 最大连续1的个数 III最大连续1的个数
用上述第一个模板,三个while循环,只需要找到关键的条件即可(即>=0),不满足则break
def longestOnes(A: List[int], K: int) -> int: L, R = 0, -1 optim = 0 while R < len(A): while R < len(A): R += 1 if R == len(A): break if A[R] == 0: K -= 1 if K < 0: #第一次不满足条件 break else: #满足条件时更新最优值 optim = max(optim, R - L + 1) if R == len(A): break while L < R: if A[L] == 0: K += 1 L += 1 if K >= 0: break return optim
class Solution: def minWindow(self, s: str, t: str) -> str: need = collections.defaultdict(int) # 记录t中字符出现次数 window = collections.defaultdict(int) # 记录窗口中响应的字符出现的次数 for c in t: need[c] += 1 left,right = 0,0 # 初始窗口长度为0 valid = 0 # 用于记录window中t中字符是否出现完,比如:t='abc',window='abd',valid就等于2.代表need中应该出现的字符在window中才出现了两个,还没有出现完全 # 记录最小覆盖子串的起始索引及长度 start = 0 length = len(s) + 1 while right < len(s): c = s[right] # 即将加入window的字符c right += 1 # 右移窗口 # 窗口内数据的一系列更新 if c in need: window[c] += 1 if window[c] == need[c]: # window中字符c出现的次数已经达到need所需要的次数时,valid进行更新 valid += 1 # 判断窗口左侧边界是否要收缩 while valid == len(need): # 在这里更新最小覆盖子串 if right-left < length: start = left length = right-left # d是将移出窗口的字符 d = s[left] # 左移窗口 left += 1 # 进行窗口内数据的一系列更新 if d in need: if window[d] == need[d]: # 这句话和下面的window[c]-=1不能反,先判断删去的字符c的数量是不是满足need的数量,如果满足,valid将减去1。 valid -= 1 window[d] -= 1 # 返回最小覆盖子串 if length == len(s) + 1: return '' else: return s[start:start+length]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。