本次总结的是链表中的环形链表,环形链表是链表的重难点之一,环形的结构有许多巧妙的地方,看看下面这道题
环形链表II(相关题号:142)
例142题目:
1.快慢指针
快慢指针是双指针法的一种经典用法,设立两个指针fast和slow,在遍历的过程中这两个指针的步幅不一样(例如本题中fast步幅为2,slow为1),这样的做法通常可以针对一些环形链表相遇问题(因为fast比slow快,有环的话是会再追上slow的)针对本题,fast步幅为2,slow为1这样再进入换之后fast一定会在某时和slow相遇,然后构造数学思维解答题目
2.判断环形的入口(结合数学思维)
利用1中所说的快慢指针当两个指针相遇的时候,这时候我们抽象分析链表各部分的情况,如下图:
可以看到slow走了x+y,fast走了x + y + n (y + z)【n为fast在环内走了几圈】,此时因为fast的速度是slow的两倍所以可以得到公式:2*(x+y)=x + y + n (y + z),可以推得x=(n-1)(y+z)+z,于是便可以得知,某个指针从头结点走x步相当于从相遇节点走(n-1)(y+z)+z步,而(n-1)(y+z)相当于走了n-1圈回到了原来的位置,某个指针从头结点走x步相当于从相遇节点走z步,而从相遇节点走z步恰好走到入环口节点!所以新设立指针index1和index2分别从头结点和相遇节点移动(步幅都为1),直到他们相遇(相等)(注意搞清楚不是fast和slow的相遇节点)既可以得到环的入口结点,概念图如下:
3.代码(Java运行出现问题所以用的c++)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
// 快慢指针相遇,此时从head 和 相遇点,同时查找直至相遇
if (slow == fast) {
ListNode* index1 = fast;
ListNode* index2 = head;
while (index1 != index2) {
index1 = index1->next;
index2 = index2->next;
}
return index2; // 返回环的入口
}
}
return NULL;
}
};