【剑指offer】9.链表中环的入口结点

总目录:

算法之旅导航目录

 

1.问题描述

给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。
数据范围: n≤100001<=结点值<=10000
要求:空间复杂度 O(1),时间复杂度 O(n)
例如,输入{1,2},{3,4,5}时,对应的环形链表如下图所示:

 

 


 

 

 
2.问题分析

注意没有尾节点,必须一次迭代就找到
可采取的方法:
1哈希表

将每个节点入表,每次入表前查询是否已存在,第一次遇到表中已存在的节点时即为入口节点

2快慢指针法(数学解法、真正符合空间复杂度O(1))

证明1:严格的证明

证明2:直观的证明

 

 

 

 


3.代码实例

哈希表

 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 };
View Code

快慢指针法

 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 };
View Code

 

posted @ 2022-11-10 19:50  啊原来是这样呀  阅读(24)  评论(0编辑  收藏  举报