题目描述
一个链表中包含环,请找出该链表的环的入口结点。
思路一:使用一个集合unordered_set<ListNode*>来保存已经访问过的结点,当第一次访问到已经被访问过的结点时,即为环的入口结点,此方法需要额外的空间进行辅助。
代码一:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead) {
ListNode* res;
while(pHead != NULL) {
if(map.find(pHead) == map.end()) {
map.insert(pHead);
} else {
res = pHead;
break;
}
pHead = pHead->next;
}
return res;
}
private:
unordered_set<ListNode*> map;
};
思路二:
采用数学分析的方法,设置快慢指针,慢指针每次前进一个结点,快指针每次前进两个结点,记相遇时的结点为q,则从q到环入口的距离与从头结点到入口的距离相等,此时从头结点和q处同时往后移动,每一移动一个结点,则相遇处即为环的入口,此方法不需要开辟额外的存储空间,更佳。
代码二:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead) {
if(pHead == NULL) return NULL;
ListNode* slow = pHead;
ListNode* fast = pHead;
while(slow && fast && fast->next){
slow = slow->next;
fast = fast->next->next;
if(slow == fast) break;
}
if(fast == NULL || fast->next == NULL) return NULL; //不存在环的情况
slow = pHead;
while(slow && fast){
if(fast == slow) return fast; //先进行判断,因为存在交点即为入口的情况
fast = fast->next;
slow = slow->next;
}
return NULL;
}
};