题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
解题思路
使用C++中的关联容器set,set 中插入单个元素的 insert 成员函数的返回值是 pair 模板类对象,假设返回结果为x,如果 x.second 为 true,则说明插入成功,此时 x.first 就是指向被插入元素的迭代器;如果 x.second 为 false,则说明要插入的元素已在容器中,此时 x.first 就是指向原有那个元素的迭代器。
根据以上知识,可以通过遍历链表,并将遍历结点插入set关联容器中,插入失败时返回的迭代器指向的就是链表中环入口的结点。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
set<ListNode*> s;
pair<set<ListNode*>::iterator,bool> res;
ListNode* p=pHead;
while(p){
res=s.insert(p);
if(!res.second) return *res.first;
p=p->next;
}
return p;
}
};
思路2
使用快指针、慢指针,假设已知链表中的环由n个结点围成,令快指针比慢指针先走n个结点,则当快慢指针相遇时,相遇结点就是环的入口。
根据以上思路还可以进一步简化:
- 令快慢指针都指向链表首元结点;
- 规定快指针每次走两步,慢指针每次走一步;
- 当快指针与慢指针第一次相遇时,可以总结两点信息:
1)此时快指针比慢指针多走了一个环;
2)快指针走的路程是慢指针所走路程的两倍,因为快指针每次走两步,慢指针每次只走一步;
综上两点易得,此时慢指针所走路程就是一个环的长度; - 重新令慢指针指向链表首元结点,快指针不动(此时相当于快指针比慢指针先走了一个环的长度);
- 快慢指针每次只向前移动一步,二者相遇的结点就是环入口结点。
/*
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* pslow=pHead->next;
ListNode* pfast=pHead->next;
if(pfast!=NULL) pfast=pfast->next;
while(pslow!=pfast && pfast){
pslow=pslow->next;
pfast=pfast->next;
if(pfast!=NULL) pfast=pfast->next;
}
if(pfast==NULL) return pfast;
pfast=pHead;
while(pslow!=pfast){
pslow=pslow->next;
pfast=pfast->next;
}
return pfast;
}
};
网友评论