LCHot100-04:子串
和为 K 的子数组
给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。
子数组是数组中元素的连续非空序列。
不能用滑动窗口,因为有负数,窗口不是单调扩张/收缩的。
tag 里有前缀和,先起一个数组把前缀和计算出来。怎么找数组呢,以每一个 index 为开头向后探一遍?这个是 ,大抵是慢了的。
这个场景比较像两数之和,只不过查找的目标变成了找符合固定两数之差的索引。
1 | class Solution { |
滑动窗口最大值
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
我写困难,真的假的?
暴力过不去,时间复杂度了。提示用双端队列 deque。
维护一个双端队列 deque,存储可能成为窗口最大值的元素下标,队列内下标对应的值严格递减。
- 每次窗口右移,新元素
nums[i]入队:将队列中所有小于nums[i]的元素下标弹出(它们已不可能成为之后窗口的最大值),然后将i加入队尾。 - 如果队首下标已滑出窗口(
队首下标 <= i - k),则弹出队首。 - 当前窗口最大值就是队首元素对应的值。
1 | class Solution { |
以 nums = [1, 3, -1, -3, 5, 3, 6, 7], k = 3 为例:
| 步骤 | 下标 i | 窗口内容 | 当前队列(下标) | 队列对应值 | 最大值 | 说明 |
|---|---|---|---|---|---|---|
| 初始 | 0 | [1] | [0] | [1] | - | |
| 1 | [1,3] | 弹出0后[1] | [3] | - | 1<3,1被淘汰 | |
| 形成窗口 | 2 | [1,3,-1] | [1,2] | [3,-1] | 3 | |
| 滑动 | 3 | [3,-1,-3] | 弹出1? 1仍合法 → [1,2,3] → 维护递减:-3入队前不弹任何,所以[1,2,3] | [3,-1,-3] | 3 | 队首1未滑出 |
| 4 | [-1,-3,5] | 检查队首1滑出 → 弹出1 → [2,3];5入队前弹出所有小于5的:2(-1)和3(-3)被弹 → [4] | [5] | 5 | ||
| 5 | [-3,5,3] | [4,5] | [5,3] | 5 | ||
| 6 | [5,3,6] | 队首4未滑出;6入队前弹5(3<6) → 队尾变为4 → 弹4(5<6) → [6] | [6] | 6 | ||
| 7 | [3,6,7] | 检查队首6滑出?6>4合法;7入队弹6(6<7) → [7] | [7] | 7 |
结果:[3,3,5,5,6,7]。
最小覆盖子串
给定两个字符串 s 和 t,长度分别是 m 和 n,返回 s 中的 最短窗口 子串,使得该子串包含 t 中的每一个字符(包括重复字符)。如果没有这样的子串,返回空字符串 ""。
测试用例保证答案唯一。
你们子串都那么变态吗…
想起来 ADS 的 KMP 了,感觉这个难得多啊…
滑动窗口?无序集合?无序集合不行,因为可能有重复元素。那就和之前一样开计数数组。用 need 记录每个字符的目标次数,window 记录当前实际次数。valid 记录种类满足情况,不是总字符数。当所有种类都满足时,窗口一定包含 t 所有字符(含重复)。找到满足窗口后,立即收缩左边界,是为了寻找更短的满足窗口。左右指针各走一遍, 时间, 额外空间(固定 128)。
1 | class Solution { |
有思路但是不会写…😭AI 怎么那么坏…



