【剑指offer】9.链表中环的入口结点
总目录:
1.问题描述
给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。
数据范围: n≤10000,1<=结点值<=10000
要求:空间复杂度 O(1),时间复杂度 O(n)
例如,输入{1,2},{3,4,5}时,对应的环形链表如下图所示:![](https://img2022.cnblogs.com/blog/1068849/202211/1068849-20221110194646617-1529222963.png)
2.问题分析
注意没有尾节点,必须一次迭代就找到
可采取的方法:
1哈希表
将每个节点入表,每次入表前查询是否已存在,第一次遇到表中已存在的节点时即为入口节点
2快慢指针法(数学解法、真正符合空间复杂度O(1))
证明1:严格的证明
证明2:直观的证明
3.代码实例
哈希表
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 struct ListNode { 3 int val; 4 struct ListNode *next; 5 ListNode(int x) : 6 val(x), next(NULL) { 7 } 8 }; 9 */ 10 class Solution { 11 public: 12 ListNode* EntryNodeOfLoop(ListNode* pHead) { 13 ListNode* pCir = pHead; 14 unordered_multiset<ListNode*> pSet; 15 16 while (pCir != NULL) { 17 if (pSet.find(pCir) != pSet.end()) { 18 break; 19 } 20 pSet.emplace(pCir); 21 pCir = pCir->next; 22 } 23 24 return pCir; 25 } 26 };
快慢指针法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 struct ListNode { 3 int val; 4 struct ListNode *next; 5 ListNode(int x) : 6 val(x), next(NULL) { 7 } 8 }; 9 */ 10 class Solution { 11 public: 12 ListNode* EntryNodeOfLoop(ListNode* pHead) { 13 ListNode* fast = pHead; 14 ListNode* slow = pHead; 15 16 while (fast) { 17 //如果快指针无法再往前走,则快慢无法相遇 18 if (fast->next == NULL) { 19 return NULL; 20 } 21 22 //快指针走两步,慢指针走一步 23 slow = slow->next; 24 fast = fast->next->next; 25 26 //等待第一次相遇 27 if (slow != fast) { 28 continue; 29 } 30 31 //已经相遇 32 fast = pHead;//重置fast 33 while (slow != fast) { 34 slow = slow->next; 35 fast = fast->next; 36 } 37 break; 38 } 39 40 return fast; 41 } 42 };