精读《算法 - 滑动窗口》

滑动窗口算法是较为入门题目的算法,一般是一些有规律数组问题的最优解,也就是说,如果一个数组问题可以用动态规划解,但又可以使用滑动窗口解决,那么往往滑动窗口的效率更高。

双指针也并不局限在数组问题,像链表场景的 “快慢指针” 也属于双指针的场景,其快慢指针滑动过程中本身就会产生一个窗口,比如当窗口收缩到某种程度,可以得到一些结论。

因此掌握滑动窗口非常基础且重要,接下来按照我的经验给大家介绍这个算法。

精读

滑动窗口使用双指针解决问题,所以一般也叫双指针算法,因为两个指针间形成一个窗口。

什么情况适合用双指针呢?一般双指针是暴力算法的优化版,所以:

  1. 如果题目较为简单,且是数组或链表问题,往往可以尝试双指针是否可解。

  2. 如果数组存在规律,可以尝试双指针。

  3. 如果链表问题限制较多,比如要求 O(1) 空间复杂度解决,也许只有双指针可解。

也就是说,当一个问题比较有规律,或者较为简单,或较为巧妙时,可以尝试双指针(滑动窗口)解法。

我们还是拿例子说明,首先是两数之和。

两数之和

两数之和是一道简单题,实际上和滑动窗口没什么关系,但为了引出三数之和,还是先讲这道题。题目如下:

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

暴力解法就是穷举所有两数之和,发现和为 target 结束,显然这种做法有点慢,我们换一种思路。

由于可以用空间换时间,又只有两个数,我们可以对题目进行转化,即通过一次遍历,将 nums 每一项都减去 target,然后找到后面任意一项值为前面的结果,即表示它们和为 target

可以用哈希表 map 加速查询,即将每一项 target - num 作为 key,如果后面任何一个 num 作为 key 可以在 map 中找到,则得解,且上一个数的原始值可以存在 map 的 value 中。这要仅需遍历一次,时间复杂度为 O(n)。

之所以说这道题,是因为这道题是单指针,即只有一个指针在数组中移动,并配合哈希表快速求解。对于稍微复杂的问题,单指针就不够了,需要用双指针解决(一般来说不会用到三或以上指针),那复杂点的题目就是三数之和了。

三数之和

三数之和是一道中等题,别以为只是两数之和的加强版,其思路完全不同。题目如下:

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 abc ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

由于超过了两个数,所以不能像双指针一样求解了,因为即便用了哈希表存储,也会在遍历时遇到 “两数之和” 的问题,而哈希表方案无法继续嵌套使用,即无法进一步降低复杂度。

为了降低时间复杂度,我们希望只遍历一次数组,这就需要数组满足一定条件我们才能用滑动窗口,所以我们对数组进行排序,使用快排的时间复杂度为 O(nlogn),时间复杂度已超出两数之和,不过因为题目复杂,这个牺牲是无法避免的。

假设从小到大排序,那我们就拿到一个递增数组了,此时经典滑动窗口方法就可用了!怎么滑动呢?首先创建两个指针,分别叫 leftright,通过不断修改 leftright,让它们在数组间滑动,这个窗口大小就是符合题目要求的,当滑动完毕时ÿ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值