如果你刚开始刷题,还不熟悉基本编程语法和常用库函数,推荐先刷力扣官方的入门题单:
有了一些简单题的积累,就可以开始刷我的题单啦~
下面的题目已按照难度分排序,右侧数字为难度分。
在刷题的过程中,如果遇到难度很大,题解都看不懂的题目,建议直接收藏,过段时间再来做。
不定长滑动窗口主要分为三类:求最长子数组,求最短子数组,以及求子数组个数。
注:滑动窗口相当于在维护一个队列。右指针的移动可以视作入队,左指针的移动可以视作出队。
一般要写 ans += left
。
内层循环结束后,[left,right] 这个子数组是不满足题目要求的,但在退出循环之前的最后一轮循环,[left−1,right] 是满足题目要求的。由于子数组越长,越能满足题目要求,所以除了 [left−1,right],还有 [left−2,right],[left−3,right],…,[0,right] 都是满足要求的。也就是说,当右端点固定在 right 时,左端点在 0,1,2,…,left−1 的所有子数组都是满足要求的,这一共有 left 个。
一般要写 ans += right - left + 1
。
内层循环结束后,[left,right] 这个子数组是满足题目要求的。由于子数组越短,越能满足题目要求,所以除了 [left,right],还有 [left+1,right],[left+2,right],…,[right,right] 都是满足要求的。也就是说,当右端点固定在 right 时,左端点在 left,left+1,left+2,…,right 的所有子数组都是满足要求的,这一共有 right−left+1 个。
思维扩展(选做)
例如,要计算有多少个元素和恰好等于 k 的子数组,可以把问题变成:
答案就是元素和 ≥k 的子数组个数,减去元素和 ≥k+1 的子数组个数。这里把 > 转换成 ≥,从而可以把滑窗逻辑封装成一个函数 f
,然后用 f(k) - f(k + 1)
计算,无需编写两份滑窗代码。
总结:「恰好」可以拆分成两个「至少」,也就是两个「越长越合法」的滑窗问题。
注:也可以把问题变成 ≤k 减去 ≤k−1(两个至多)。可根据题目选择合适的变形方式。
注:也可以把两个滑动窗口合并起来,维护同一个右端点 right 和两个左端点 left1 和 left2,我把这种写法叫做三指针滑动窗口。
刷题路线请看 如何科学刷题。
两个指针 left=0, right=n−1,从数组的两端开始,向中间移动,这叫相向双指针。上面的滑动窗口相当于同向双指针。
两个指针的移动方向相同(都向右,或者都向左)。
相似题目:
两个指针从数组中的同一个位置出发,一个向左,另一个向右,背向移动。
思维扩展(选做):
进阶:
注:部分题目已整理到「§2.3.3 恰好型滑动窗口」中。
思维扩展:
适用场景:按照题目要求,数组会被分割成若干组,每一组的判断/处理逻辑是相同的。
核心思想:
这个写法的好处是,各个逻辑块分工明确,也不需要特判最后一组(易错点)。以我的经验,这个写法是所有写法中最不容易出 bug 的,推荐大家记住。
做了一些题目后,请总结:滑动窗口和双指针的区别是什么?
欢迎在评论区发表你的做题总结。
如果你发现有题目可以补充进来,欢迎评论反馈。