首先快慢指针是指 两个指针移动速度不一样,比如 fast 指针每次移动长度为2,slow 指针每次移动长度为 1 ,这样如果链表中存在环的话,fast 指针和 slow 指针一定会相遇
快慢指针可以解决什么问题?
- 判断链表是否有环
- 寻找链表的中点,(fast指针走到终点的时候,slow走到中点)
- 寻找链表的倒数第k个节点 (设 fast = slow + k,fast 走到链表末尾时,slow走到倒数第k个节点)
- 寻找链表的入环点 (先得到相遇指针,在让慢指针与相遇指针一起走,相遇的点就是入环点)
- 求有环链表的环长 (第一次相遇后,让快慢指针继续跑,第二次相遇时,两者步数之差就为环长)
寻找链表的入环点
如图所示,如果链表中存在环,fast 指针和 slow 指针一定在环中相遇
这时
fast 指针走过的距离为:
d
i
s
(
f
a
s
t
)
=
x
+
y
+
n
∗
(
y
+
z
)
dis(fast) = x + y + n*(y + z)
dis(fast)=x+y+n∗(y+z)
slow 指针走过的距离为:
d
i
s
(
f
l
o
w
)
=
x
+
y
dis(flow) = x + y
dis(flow)=x+y由于 slow 指针走一步,fast 指针走 两步,所以
2
∗
d
i
s
(
s
l
o
w
)
=
d
i
s
(
f
a
s
t
)
2 * dis(slow) = dis(fast)
2∗dis(slow)=dis(fast)
即:
2
∗
(
x
+
y
)
=
x
+
y
+
n
∗
(
y
+
z
)
2 * (x + y) = x + y + n * (y + z)
2∗(x+y)=x+y+n∗(y+z)
化简得到:
x
+
y
=
n
∗
(
y
+
z
)
x + y = n * (y + z)
x+y=n∗(y+z)
等式成立的条件是:
x
=
z
x
=
y
+
2
z
=
z
+
(
y
+
z
)
x
=
2
y
+
3
z
=
z
+
2
(
y
+
z
)
⋯
x
=
n
y
+
(
n
+
1
)
z
=
z
+
n
(
y
+
z
)
\begin{aligned} & x=z \\ & x=y+2 z=z+(y+z) \\ & x=2 y+3 z=z+2(y+z) \\ & \cdots \\ & x=n y+(n+1) z=z+n(y+z)\end{aligned}
x=zx=y+2z=z+(y+z)x=2y+3z=z+2(y+z)⋯x=ny+(n+1)z=z+n(y+z)
(y + z)代表走一圈的距离
所以让 fast 指针和 slow 指针相交处的指针,绕环移动
那么这个指针走到入环点的距离是
z
+
n
(
y
+
z
)
z + n(y + z)
z+n(y+z)
所以相遇指针和指向头节点的指针,同时开始移动,必然会在入环点相遇。
fast 指针每次移动 3 步是否可行? 4步,5步呢?
设 fast 指针每次走 k 步,环的长度为 s,并且 fast 指针和 slow 指针在第 n 圈的时候相遇,相遇点为 y
那么得到等式
k
∗
(
x
+
y
)
=
x
+
y
+
n
∗
s
k * (x + y) = x + y + n * s
k∗(x+y)=x+y+n∗s
化简得:
(
k
−
1
)
∗
(
x
+
y
)
=
n
∗
s
(k - 1) * (x + y) = n * s
(k−1)∗(x+y)=n∗s
将(y + z)除过去,得:
(
x
+
y
)
=
n
∗
s
k
−
1
(x + y) = \dfrac{n * s }{k - 1}
(x+y)=k−1n∗s
其中 x,s 是确定的,变量 步长 k 和 相遇点 y ,和 圈数 n
…
证不出来,希望有那位佬可以帮忙从数学式子的角度证明一下
上另外一种好理解的证明方法:
假设,慢指针步长为 1,快指针步长为 k,环入口到链表起点距离为 x,环的长度为 s.
因为慢指针是一步一步走,所以可以遍历到链表中的每一个点,所以我们可以假设他们会相遇再任意一个节点
设 快慢指针 相遇点为 y 且 y 为 s 的整数倍,且 y > x; 那么 y 就表示 选取快慢指针相交的点。
那么此时快指针走过的距离为 ky,快慢指针的路径差为 (k - 1) * y; 因为 y 是 s 的整数倍,所以快慢指针肯定能遇见。
根据上面的假设有式子:(k - 1)y = (k - 1)ns,s是确定的,n可以取满足 y 大于 x 的最小值,所以k - 1越小,相遇的越快,当 k = 2 时,有最小值
题目打卡
下面四道题中,前面两道可以用双指针来做,后面两道可以用快慢指针来做。