209.长度最小的子数组
思路
滑动窗口:直接运用双指针(同向)方法的框架,fast和slow框起来的就是需要移动的窗口。改变窗口的位置需要移动左右边界。
右边界:fast依次向后遍历即可,所执行的还是“查询”工作,由for in range实现;
左边界:在右边界移动后出现当前的sum >= target的时候移动,缩小子序列范围。注意!这里的移动不是移动一次就交给fast移动了,而是持续移动slow直到sum < target为止,所以我们这里需要的不止是if的一次性判断,而是持续的循环,所以使用while。
这里没有采取随想录的return写法,因为太高级了没想到(悲);另外一方面也是flag的用法突然就想到了,所以用一下。
class Solution(object):
def minSubArrayLen(self, target, nums):
"""
:type target: int
:type nums: List[int]
:rtype: int
"""
result = 100001 # 题目所示最大的数组长度
sublen = 0 # 保存记录当前的子序列长度,用来和上一次的result取最小值
slow, fast = 0, 0 # 这里还是选取使用快慢指针
sum = 0 # 保存当前的子序列和
flag = 0 # 判断result是否发生改变
for fast in range (len(nums)):
sum += nums[fast] # 只要fast移动,就多加一个
while sum >= target: # 注意!!我们要让slow能够“一直往前”缩小区间,就需要一直判断,所以用while不是if
sublen = fast - slow + 1 # 区间长度,注意是索引的差值 + 1
result = min(result, sublen) # 上一轮result和当前的子序列长度取小
sum -= nums[slow] # 往前移动slow之前,总和也需要剪掉当前的slow对应的值
slow += 1 # 往前移动一格
flag =1 # 表示现在的result被修改了,也就是说存在最小的子序列
if flag: # 存在最小的子序列,返回result
return result
return 0 # 不存在
904.水果成篮
思路
本题的思路是使用一个哈希表,记录当前的滑动窗口中,每种水果出现的次数“key - value”。由于只能最多出现2种水果,所以在遇到第3种的时候持续移动left,这就是while的判据。
另外,本题使用了一个新的方法Counter():作用就是记录每一个key对应出现的次数,本题单独创建,可以理解为字典。还有一个新的迭代方法enumerate():返回可迭代对象(这里的fruits列表)的每一个元素(x)和对应的索引(right)。
class Solution(object):
def totalFruit(self, fruits):
"""
:type fruits: List[int]
:rtype: int
"""
cnt = Counter()
# 可以理解成一个计数用的字典“key -- value”,其中key是元素的种类,value是该种类出现的次数
left = 0 # 定义起始点
ans = 0 # 定义最终长度
for right, x in enumerate(fruits):
# enumerate迭代器方法:返回第 1 个是索引,第 2 个是迭代对象的内容,在这里x是fruits里面的值,right是对应的位置
cnt[x] += 1 # 每次right移动,就要在对应的水果种类上 + 1
while len(cnt) > 2:
# 通常情况下,cnt的长度只能是最多3个(元素种类的上限是2)
cnt[fruits[left]] -= 1 # 位移left的同时需要把对应的计数次数 - 1
if cnt[fruits[left]] == 0: # 当key对应的value是0,也就是不存在当前水果的时候,删除这个key
cnt.pop(fruits[left])
left += 1 # 移动left
ans = max(ans, right - left + 1) # 每次走完一个while,也就是当前只有2个key的时候,记录一下ans最小值
return ans
76.最小覆盖子串
思路
和上一题一样,我们创建一个哈希表来保存t中的“key - value”。但是涉及到的判断较多:
1、在right每移动1格之后,判断哈希表中对应字符还需要的个数,如果当前right指向的是需要的,即value大于0,那就纳入序列,同时哈希表中对应的value - 1;
2、当t的全部字符都被满足(此时right已经纳入了全部的t中的字符个数,长度为0),就需要移动left,这里判断后的循环退出的条件是,当前left移动的位置使得哈希表对应字符的value恰好=0。
class Solution(object):
def minWindow(self, s, t):
"""
:type s: str
:type t: str
:rtype: str
"""
t_cnt = Counter(t) # cnt是可变量,开一个哈希表来表示t中的 key - value
t_len = len(t) # 可变量,表示当前t的长度,全部包含时 == 0
left = 0 # 左指针在遇到满足条件时移动
ans = (0, float('inf')) # 保存当前的左右边界最小的情况,ans[1]是右边界,ans[0]是左边界
for right, x in enumerate (s):
if t_cnt[x] > 0: # 如果此时right所指位置的元素在t中还有“余量”,也就是没有全部包含
t_len -= 1 # right所指的元素纳入序列,相应的t还需要填充的长度-1
# Step 1:把当前的x纳入子序列
t_cnt[x] -= 1
# Step 2:如果此时t被满足,那么我们就找到了一个“可行的序列”,进入移动
if t_len == 0:
while 1:
# 判断当前left的元素是否已经满足要求
temp = s[left]
if t_cnt[temp] == 0: # 若已经满足“恰好 == 0”,直接退出,因为这个元素是“必要的”,删除会导致不足
break
t_cnt[temp] += 1 # 如果不是,去掉一个之后相应的元素计数需要+1
left += 1
ans = (left, right) if ans[1] - ans[0] > right - left else ans # 每次while走完,left更新完保存当前最小的ans
return '' if ans[1] > len(s) else s[ans[0]: ans[1] + 1]
数组总结
本人偷懒,但是看到随想录星球里面已经有老哥总结了mindmap,所以引用如下:
第二天完结🎉