一、快慢指针原理
1、一般步骤
- Step1:从起点A开始,快指针每次走两步,慢指针每次走一步;当两个指针相遇时(假设相遇点为C)下一步。
- Step2:再从起点A开始,设立一个慢指针,两个慢指针一起每次走一步;两个慢指针相遇的位置就是环入口B。
2、原理分析
1、假设A到B距离为a,B到C距离为b,C到B距离为c(顺时针)。
2、快慢指针相遇时,两个指针走过的距离及关系
- 快指针:a+m(b+c)+b,m圈
- 慢指针:a+n(b+c)+b,n圈
- 快指针每次走2步,慢指针每次走1步,所以有:a+m(b+c)+b=2[a+n(b+c)+b],得到a+b=(m-2n)(b+c) (1)式。
- 当慢指针第一次到达B时,快指针已经在环上走了k圈了,慢指针在环上走了n圈,所以快指针又走了2n圈,得到m-2n=k (2)式。
- (2)代入(1)得到a=(k-1)(b+c)+c,所以当慢指针1从A走a步到达B时,慢指针2正好从C走k-1圈+c步到达B,即正好相遇在B点。
二、例题:寻找重复数(来源:LeetCode)
public static int findDuplicate(int[] nums) { // 快慢指针从起点开始,快指针每次走2步,慢指针每次走1步,找到在环中相遇位置 int tortoise = nums[0]; int hare = nums[0]; do { tortoise = nums[tortoise]; hare = nums[nums[hare]]; } while (tortoise != hare); // 慢指针从相遇位置继续走,再加一个慢指针从起点开始,两个慢指针相遇的位置就是环的入口 int ptr1 = nums[0]; int ptr2 = tortoise; while (ptr1 != ptr2) { ptr1 = nums[ptr1]; ptr2 = nums[ptr2]; } return ptr1; }