1.暴力解法:找到环中的任一位置,然后遍历链表,找到第一个在环中的结点,这个结点就是入口结点 50ms
class Solution { public: ListNode* EntryNodeOfLoop(ListNode* pHead) { ListNode* fast = pHead; ListNode* slow = pHead; //如果没有环,则返回空指针 if(fast == nullptr || fast->next == nullptr) { return nullptr; } while(fast && fast->next) { //如果没有环,则返回空指针 if(fast->next->next == nullptr) { return nullptr; } fast = fast->next->next; slow = slow->next; if(fast == slow) break; }//循环完成后fast指向环中的某一结点 //遍历链表,找到第一个在环中的结点,这个结点就是入口结点 while(pHead) { int flag = 0;//标记 ListNode* temp = fast;//记录fast的初始位置 //如果pHead与fast不相等,则遍历环找寻pHead是否在环中 while(pHead != fast) { fast = fast->next; //如果找了一圈也没有,则退出,并将标记置1 if(fast == temp) { flag = 1; break; } } //如果pHead不在环中,则继续遍历下一个结点 if(fast == temp && flag == 1) pHead = pHead->next; else //如果在,则说明找到了,退出循环 break; } return pHead; } }
2. 解题思路:参考官方解题思路,表头到相遇点的距离为x+y,环的大小为y+z,并且 x+y = n*(y+z),所以环入口x = n*(y+z)-y,y为环入口到相遇点的距离。
当n=1时,x=z,z为相遇点到环入口的距离,当n = n时,x = n*环长+z
这样如果让一个指针从头开始遍历,一个指针从相遇点开始遍历,这样当它们再次相遇时,相遇点就是环的入口,因为环入口到相遇点的距离为y,这样当它绕n圈并+z以后,刚好就在环入口点
6ms
class Solution { public: ListNode* EntryNodeOfLoop(ListNode* pHead) { //如果为空链表,则返回空 if(!pHead) return nullptr; ListNode* fast = pHead; ListNode* slow = pHead; while(fast && fast->next) { fast = fast->next->next; slow = slow->next; if(fast == slow) { //重新让slow从头开始走 slow = pHead; //相遇时停止 while(slow != fast) { slow = slow->next; fast = fast->next; } return slow; } } return nullptr;//如果没有环,则返回空指针 } }
3. 解题思路2:哈希法,使用集合set
- 遍历单链表的每个结点
- 如果当前结点地址没有出现在set中,则存入set中
- 否则,出现在set中,则当前结点就是环的入口结点
- 整个单链表遍历完,若没出现在set中,则不存在环
8ms
class Solution { public: ListNode* EntryNodeOfLoop(ListNode* pHead) { set<ListNode*> set; while(pHead) { if(set.find(pHead) == set.end()) { set.insert(pHead); pHead = pHead->next; } else return pHead; } return nullptr; } }