大家好,继续刷题,这次一道找环形链表入环点的题,看下题目要求:
思路:1.我看了剑指offer上对这道题的解读,首先是快慢指针判断是否有环,针对快慢指针的方法参考我的这一篇博客
判断完以后,设置一个指针temp指向相遇点并原地循环一周,再次回到快慢指针相遇的这个结点时算出这个环总共包含多少结点,结点数设为n。然后让快慢指针都回到head,再让快指针提前走n步,然后快慢指针同时每次走一步,相遇的结点即为入环结点。
如图,链表的总长度为a + n,fast提前走了n,当fast和slow共同走了a步时,slow走到入环结点,fast走了一整个链表的长度因此走到了链表的尾部,也是入环结点处,因此此时fast和slow相遇了。代码如下:
/**
* 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) {
if(head == nullptr)
return nullptr;
ListNode * slow = head;
ListNode * fast = head;
ListNode * temp = nullptr;
int node = 1;
while(fast -> next != nullptr){
slow = slow -> next;
fast = fast -> next;
if(fast -> next != nullptr)
fast = fast -> next;
else return nullptr;
if(slow == fast){
temp = slow;
break;
}
}
if(temp != nullptr){
while(temp -> next != slow){
temp = temp -> next;
node++;
}
slow = head;
fast = head;
for(int i = 0;i < node;i++){
fast = fast -> next;
}
while(slow != fast){
slow = slow -> next;
fast = fast -> next;
}
return slow;
}
else return nullptr;
}
};
这种方法虽然挺好的,但是在leetcode里跑会超时。
2.第二种方法也是先用快慢指针判断是否有环,然后如上图所示,相遇点到入环结点的距离为b。可以看到在相遇时fast走的路径是slow的两倍,由此可以推算出a = c。所以在两指针相遇后只让slow回到head,然后slow和fast每次各走一步,当fast走了c时slow走了a,两指针再次相遇,此时就是入环结点。代码如下:
/**
* 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) {
if(head == nullptr)
return nullptr;
ListNode * slow = head;
ListNode * fast = head;
ListNode * temp = nullptr;
int node = 1;
while(fast -> next != nullptr){
slow = slow -> next;
fast = fast -> next;
if(fast -> next != nullptr)
fast = fast -> next;
else return nullptr;
if(slow == fast){
temp = slow;
break;
}
}
if(temp != nullptr){
slow = head;
while(slow != fast){
slow = slow -> next;
fast = fast -> next;
}
return slow;
}
else return nullptr;
}
};
好了,我们下期见!