双指针算法

用两个指针,在数据结构中遍历和操作,以高效地解决问题。

一般有快慢指针、左右指针这2种方式。

1. 快慢指针

1.1. 有两种“快慢”方式

  • 【方式1】每次迭代快指针都走1步,慢指针在满足某个条件的时候才走;
  • 【方式2】每次迭代快指针都走n步(n≥2),慢指针走1步。

1.2. 常见解决的解决问题

1.2.1. 使用【方式1】解决的问题

1.2.1.1. 顺序中找重(或去重)

快指针每次都走1个节点,当快慢指针的值不一样时,慢指针走到快指针处,一样时(这时候就找到重复了)慢指针不走。

具体来说如下:

两个指针都指向排好序的数组中的第一个元素,一个for循环从第2个开始遍历,快指针指向新的元素,如果新的元素跟慢指针指向的元素值一样,慢指针就不动(这时候已经找到重复了),如果不一样,慢指针就指向快指针指向的新元素。

左手拿一个,右手拿下一个,当右手的跟左手的一样的时候,说明找到重复的了,直接把右手的扔掉,继续拿下一个,直到下一个跟左手的不一样,然后把右手的给左手,右手继续拿下一个。

1.2.1.2. 找到单链表中倒数第k个节点

快指针先走k个节点,然后快慢指针一起走,当快指针走到结尾了,慢指针就是倒数第k个节点。

我持一把k米的刀地往前冲,当刀尖(快指针)碰到墙壁时,我(慢指针)离墙(链表尾)就是k米。7cdaf26f7e7b4deca57390f0927c4be1.jpg

1.2.1.3. 移动零

问题:把一个数组中的0移到末尾,如输入[0,1,0,3,12],输出[1,3,12,0,0]

解法:快指针每次走一步,快指针指向的元素不为0时,跟慢指针指向的值交换一下,同时慢指针走一步。快指针走过的元素,表示被处理过的元素;慢指针右边到快指针左边全是0,慢指针不一定是0。

4e4b88bf69704c66b15c8536bc3f7756.jpg

 

有一排装着花的盒子,有些盒子里的花蔫了。小红和小明准备把蔫了的盒子放在一起,他们这样做:

小红和小明最开始站在第一盒花前面,小明开始从左向右一盒一盒地检查,当发现有蔫了花的盒子,小明就继续往右走,如果发现鲜花,他就开心地把这盒花跟小红的那盒换一下,同时小红站在下一盒面前。当小明走到最右边,他们的任务就做完了。01bceee934d2494298d70f2a1ee02f03.jpg

 

1.2.2. 使用【方式2】解决的问题

1.2.2.1. 判断链表中的环

每次快指针走2个节点、慢指针走1个节点,当两者相遇的时候,就有环,如果快指针走完全程都没跟慢指针相遇,说明没有环。

在一个环形赛道上,两人同时起跑,一个快,一个慢。快的人一定会在某个时刻追上慢的人。

1.2.2.2. 【引申问题】找到有环链表中,环的起点

这是上一个问题“判断链表中的环”引申的一个问题。解法如下:

按“判断链表中的环”的方式,快慢指针相遇的时候,再派一个新指针站在链表开头,然后这个新指针跟原来的慢指针再一起走,每次走1个节点,当他们俩相遇的时候,就是环的起点。

如下图,A是链表起点、B是环入口点、C是快慢指针相遇点,x是AB间的距离、y是BC间的距离,z是CB间的距离。根据"快指针走过的距离"=2倍"慢指针走过的距离",有x+y+z+y = 2(x+y),等式两边都减去一个x+y得到z+y=x+y,即z=x。所以新指针从A、原来的指针从C,他们一起相同速度出发,会在B点相遇,B点即环的起点。f7911d1bdbed456b969516807f8b1004.jpg

1.2.2.3. 找到单链表中间的节点

每次快指针走2个节点、慢指针走1个节点,当快指针走完的时候,慢指针就指向的是中间的节点。

队伍中,一人正常前进,另一人两倍速前进。快的人到队尾时,慢的人正好在队伍中间。

2. 左右指针

2.1. 思路

两个指针,一个在开始位置,一个在末尾位置,根据特定条件向中间移动指针,来解决问题。

2.2. 常见解决的问题

2.2.1. 两数之和

问题:从一组数中找到相加等于某个值的两个数出来。

解法:先将这一组数排序,比如从小到大排序,左右指针分别在排序后数组的开头和结尾位置,然后计算这两个指针指向的值的和,如果和大于要求的值,右指针左移,如果和小于要求的值,左指针右移,如果相等,就找到了,如果左右指针相撞,就说明不存在这两个数。

多了就减点,左移;少了就加点,右移

2.2.2. 回文判断

左右指针分别在数组的开头和结尾位置,然后一起往中间移动,移动一次比较一次,如果左右指针的值不一样,说明不是回文。

2.2.3. 盛水最多的容器

c0da8684b22c4d94914d20fd0704e949.jpg

 

问题:输入[1,8,6,2,5,4,8,3,7],输出49。解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为49。

解法:左右指针分别在数组的开头和结尾位置,如果固定小边,大边往中间移动,面积必然减少,所以固定大边,移动小边。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值