題目描述
一個鏈表中包含環,請找出該鏈表的環的入口結點。
方法一:
對鏈表進行遍歷,利用set等結構,將已經遍歷過的節點存入set,每遍歷一個節點,判斷set中是否已經存在該節點,如果存在,那麼說明鏈表存在環,且該節點就是入口節點,返回該節點;如果遍歷到NULL,說明已經到了鏈表結尾,說明該鏈表不存在環,返回NULL。代碼
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if( pHead == NULL || pHead->next == NULL )
return NULL;
unordered_set<ListNode*> s;
ListNode* p = pHead;
while( p )
{
if( s.find(p) != s.end() )
return p;
s.insert(p);
p = p->next;
}
return NULL;
}
};
方法二:
1、判斷是否存在環:利用兩個指針,同時從鏈表的頭節點出發,一個指針一次走一步,另一個指針一次走兩步,如果兩個指針相遇,則存在環;如果兩個指針中任意一個等於NULL,說明不存在環。可以將相遇時的指針返回,後面會用到。
2、找環的入口:
首先判斷環中節點個數,利用前面找到的相遇時的節點,該節點一定是在環中的,可以從該節點出發,一邊向前一邊計數,再次回到該節點時,就可以得到環中節點個數n了。
建立兩個指針p1和p2,令p1先走n不,然後p1和p2以相同速度向前移動,直到他們相遇,他們相遇的節點就是環的入口,如下圖所示。
代碼
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if( pHead == NULL || pHead->next == NULL )
return NULL;
ListNode* meetingNode = MeetingNode(pHead);
if( meetingNode == NULL )
return NULL;
ListNode* p = meetingNode->next;
int count = 0;
while( p != meetingNode )
{
count++;
p = p->next;
}
p = pHead;
for( int i=0;i<=count;i++ )
p = p->next;
ListNode* p2 = pHead;
while( p != p2 )
{
p = p->next;
p2 = p2->next;
}
return p;
}
ListNode* MeetingNode(ListNode* pHead)
{
ListNode* p1 = pHead->next;
ListNode* p2 = pHead->next->next;
while( p1 != NULL && p2 != NULL )
{
if( p1 == p2 )
return p1;
p1 = p1->next;
p2 = p2->next;
if( p2 != NULL )
p2 = p2->next;
else
return NULL;
}
return NULL;
}
};