链表中环的入口结点
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
题解: 首先是确定链表中有环,第二步是找到链表的入口。
在确定是否有环的过程中,设置一个快指针,一个慢指针,快指针一次走两步,慢指针一次走一步,如果两个指针可以相遇,证明存在环。
在找链表入口结点的过程中,定义两个指针p1、p2指向链表的头结点. 如果环中有n个结点将p1先在链表上向前移动n步,然后两个结点同时前进,相遇点就是环的入口结点。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead){
if(pHead == nullptr){
return nullptr;
}
ListNode* loopNode = nodeInLoop(pHead);
if(loopNode == nullptr)
return nullptr;
ListNode* firstLoop = loopNode->next;
int count = 1;
// 统计环中的个数
while(loopNode != firstLoop){
count++;
firstLoop = firstLoop->next;
}
firstLoop = pHead;
ListNode* end = pHead;
// 前进n个点
while(count-- > 0){
firstLoop = firstLoop->next;
}
while(end != firstLoop){
end = end->next;
firstLoop = firstLoop->next;
}
return firstLoop;
}
//找到环中的结点
ListNode* nodeInLoop(ListNode* pHead){
if(pHead == nullptr){
return nullptr;
}
ListNode* lowPoint = pHead;
ListNode* fastPoint = nullptr;
if(pHead->next != nullptr)
fastPoint = lowPoint->next;
else
return nullptr;
while(fastPoint != lowPoint && fastPoint != nullptr){
lowPoint = lowPoint->next;
fastPoint = fastPoint->next;
if(fastPoint != nullptr)
fastPoint = fastPoint->next;
}
return fastPoint;
}
};
解法二:
因为节点的地址都是不重复的,可以将节点的地址存放到一个set里面,在存放的过程中。
1》如果发现一个节点已经存在,那么这个节点就是入口节点,
2》如果遇到了链表的尾巴,都没有重复的,那就是没有存在环。
/**
* 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;
}
set<ListNode*> nodes;
ListNode* point = head->next;
nodes.emplace(head);
while(point != nullptr && nodes.find(point) == nodes.end()) {
nodes.emplace(point);
point = point->next;
}
if(point == nullptr){
return nullptr;
}
return point;
}
};