3.无重复字符的最长子串 mid
思路
一次遍历
借助HashSet,加入右指针遍历过的元素, 检查重复。
无重复 -> 加入set -> 右指针继续移动
有重复 -> 左指针指向的元素出set -> 左指针缩短左边界 -> 加入set -> 右指针继续移动
最长字串长度:right - left + 1
239. 滑动窗口最大值 hard
思路
1. 使用 双端队列 表示 滑动窗口,并且是单调队列
头:删除过期元素,位置 i-k
尾:维护单调递减,加入新元素
此时队列第一个元素就是最大值
2. 单调队列存储的是 数组下标
Deque
(双端队列)是 Java 中的一种数据结构,允许从两端插入和删除元素。常用方法:
添加元素
void addFirst(E e)
:在双端队列的头部插入元素。void addLast(E e)
:在双端队列的尾部插入元素。boolean offerFirst(E e)
:在头部插入元素,如果成功返回true
,否则返回false
。boolean offerLast(E e)
:在尾部插入元素,如果成功返回true
,否则返回false
。移除元素
E removeFirst()
:移除并返回头部的元素。如果队列为空则抛出异常。E removeLast()
:移除并返回尾部的元素。如果队列为空则抛出异常。E pollFirst()
:移除并返回头部的元素,如果队列为空则返回null
。E pollLast()
:移除并返回尾部的元素,如果队列为空则返回null
。查看元素
E getFirst()
:返回头部的元素但不移除,如果队列为空则抛出异常。E getLast()
:返回尾部的元素但不移除,如果队列为空则抛出异常。E peekFirst()
:返回头部的元素但不移除,如果队列为空则返回null
。E peekLast()
:返回尾部的元素但不移除,如果队列为空则返回null
。其他方法
int size()
:返回双端队列中的元素数量。boolean isEmpty()
:检查双端队列是否为空。void clear()
:移除双端队列中的所有元素。
窗口右边队头,左边队尾
76.最小覆盖字串
思路
滑动窗口
这道题要求我们返回字符串 s中包含字符串 t 的全部字符的最小窗口,我们利用滑动窗口的思想解决这个问题。
因此我们需要两个哈希表
hs哈希表维护的是s字符串中滑动窗口中各个字符出现多少次
ht哈希表维护的是t字符串各个字符出现多少次。
如果hs哈希表中包含ht哈希表中的所有字符,并且对应的个数都不小于ht哈希表中各个字符的个数,那么说明当前的窗口是可行的,可行中的长度最短的滑动窗口就是答案。
过程如下:
1、遍历t字符串,用ht哈希表记录t字符串各个字符出现的次数。
2、定义两个指针 left 和 right,left 指针用于收缩窗口,right指针用于延伸窗口,则区间[left,right]表示当前滑动窗口。首先让i和j指针都指向字符串s开头,然后枚举整个字符串s ,枚举过程中,不断增加i使滑动窗口增大,相当于向右扩展滑动窗口。
3、每次向右扩展滑动窗口一步,将s[right]加入滑动窗口中
4、对于新加入的字符s[i],如果hs[s[right]] <= ht[s[right]],说明当前新加入的字符s[i]是必需的,且还未到达字符串t所要求的数量。
需要事先定义一个cnt变量, cnt维护的是s字符串[left,right]区间中满足t字符串的元素的个数,记录相对应字符的总数。新加入的字符s[right]必需,则cnt++。
5、扩展滑动窗口的同时也收缩滑动窗口。如果左边界的值不在ht表中 或者 它在hs表中的出现次数多于ht表中的出现次数,此时我们就需要向右收缩滑动窗口,j++并使hs[s[left]]--
6、当cnt == t.size时,说明此时滑动窗口包含符串 t 的全部字符。我们重复上述过程找到最小窗口即为答案。
时间复杂度分析: 两个指针都严格递增,最多移动 n 次,所以总时间复杂度是 O(n)。