【完虐算法系列】「字符串 – 滑动窗口」复盘总结 (2)

代码简单的写一下,还是利用 Python,也是因为 Python 的话,绝大多数人还是比较熟悉。

class Solution(object): def sumSlidingWindow(self, s, w): sum = 0 res = [] # 计算第一个窗口数字之和 for item in range(5): sum += s[item] res.append(sum) # 后面利用滑动窗口思想进行计算 for item in range(w, len(s)): sum -= s[item-w] sum += s[item] res.append(sum) return res

下面咱们用三个 LeetCode 经典案例进一步阐述滑动窗口这类题目。

滑动窗口经典题目 567.字符串的排列【中等】

给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。

换句话说,s1 的排列之一是 s2 的 子串 。

输入:s1 = "ab" s2 = "eidbaooo" 输出:true 解释:s2 包含 s1 的排列之一 ("ba").

首先,两个字符串的排列,首先可以想到字典,根据字典去比较。

词典可根据两个不同字符串将给到的字符进行计数,因此,这样很同容易进行比较。

另外,在遍历 s2 的时候,使用滑动窗口,该窗口的长度是字符串 s1 的长度,遍历 s2 使得字符不断的出入,在此过程中比较两个字典。

整个过程,记 s1 的长度为 size1,s2 的长度为 size2,窗口大小为 size1,不断遍历 s2,直到 s2 的结尾。

记 s1 的字典为 dict_s1,记s1的字典为dict_s2,在遍历s2的过程中,每滑动一次窗口,比较 dict_s1 和 dict_s2 是否相等。

窗口滑动过程中,需要删除滑出窗口的元素以及新增滑入窗口的元素

删除滑出窗口的元素:广义上是从字典 dict_s2 中删除,注意此处不能直接删除,因为可能会有重复元素存在,比如:{'a':2},所以只能是将 value 值减 1。之后再判断 value 值为否为 0,如果为 0 了,这个时候就可以直接将该元素从字典中删除。

新增滑入窗口的元素:直接将滑入窗口的元素添加进字典中。

下面用几个图清晰的一步一步操作:

初始化 s1 对应的字典 dict_s1={'a':1,'b':1}

① s2 对应的字典为图中窗口中的元素 dict_s2={'e':1,'i':1}。

最后判断 dict_s1 != dict_s2

【完虐算法系列】「字符串 – 滑动窗口」复盘总结

② 向右滑动窗口,由于元素e的 value 值为 1,直接删除该元素,加入新元素d,此时,dict_s2={'i':1,'d':1}。

最后判断 dict_s1 != dict_s2

【完虐算法系列】「字符串 – 滑动窗口」复盘总结

③ 继续向右滑动窗口,由于元素 i 的 value 值为 1,直接删除该元素,加入新元素 b,此时,dict_s2={'d':1,'b':1}。

最后判断 dict_s1 != dict_s2

【完虐算法系列】「字符串 – 滑动窗口」复盘总结

③ 继续向右滑动窗口,由于元素 d 的 value 值为 1,直接删除该元素,加入新元素 a,此时,dict_s2={'b':1,'a':1}。

最后判断 dict_s1 == dict_s2 ,此时可以直接返回 True。不用在继续窗口滑动了。

【完虐算法系列】「字符串 – 滑动窗口」复盘总结

这个题虽然在 LeetCode 中标记为中等,但是用滑动窗口的方式去解决还是非常容易理解的。

下面是 Python 代码的实现:

class Solution(object): def checkInclusion(self, s1, s2): size1 = len(s1) size2 = len(s2) if size1 > size2: return False dict_s1 = collections.Counter(s1) dict_s2 = collections.Counter(s2[:size1-1]) left = 0 for right in range(size1-1, size2): # 增加新添加的元素 dict_s2[s2[right]] += 1 # 判断如果字典相同,则返回 True if dict_s1 == dict_s2: return True # 删除左边剔除的元素(首先需要将左边元素的 value 值减 1) dict_s2[s2[left]] -= 1 # value 值为 0 的时候,就可以删除该元素了 if dict_s2[s2[left]] == 0: del(dict_s2[s2[left]]) # 窗口整体向右移动一格 left += 1 right += 1 return False

下面再看一个稍微复杂一点的,也是滑动窗口的典型例题。

239.滑动窗口最大值【困难】

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回滑动窗口中的最大值。

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7] 解释: 滑动窗口的位置 最大值 --------------- ----- [1 3 -1] -3 5 3 6 7 3 1 [3 -1 -3] 5 3 6 7 3 1 3 [-1 -3 5] 3 6 7 5 1 3 -1 [-3 5 3] 6 7 5 1 3 -1 -3 [5 3 6] 7 6 1 3 -1 -3 5 [3 6 7] 7

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgddzg.html