题目描述
给定一个链表,若其中包含环,则输出环的入口节点。
若不包含环,则输出null。
样例
Input: 如图示链表:1->2->3->4->5->6
Output: 2(下标为2的节点)
解题思路
-
描述
用一张图形象地描述该问题(该图来自www.acwing.com):
假定这是一个带环的链表,a为链表首部节点,b为环的入口节点,c为环中的某一节点。a、b相距x,b、c相距y,圈长度为l。
使用两个指针first和second分别从a出发,first每次走一步,second每次走两步。
容易知道,对于带环的链表,first和second一定会在环中的某一节点相聚,假定这一节点就是c。
假定当first和second相聚时,second在环中已转圈a圈(first并没有转圈0圈,可以通过举例得出该结果)。那么有 2 ( x + y ) = x + a l + y ⇔ x + y = a l 2(x + y) = x + al + y \Leftrightarrow x + y = al 2(x+y)=x+al+y⇔x+y=al
因此,当first和second相聚时,令first从a开始出发,second从c继续出发,两者每次均走一步,两者再次相聚之处便是b。 -
实现代码:
/* struct ListNode { int val; struct ListNode* next; }; */ ListNode* entryNodeOfLoop(ListNode* head) { struct ListNode* i = head, *j = head; while (i && j) { i = i->next; j = j->next; if (j) { j = j->next; if (j == NULL) // j走到链表尾部,证明不存在环 return NULL; } if (i == j) // 此时相遇 { break; } } i = head; while (i && j) { i = i->next; j = j->next; if (i == j) // 再次相遇,返回即可 { return i; } } }
-
复杂度分析
时间复杂度:\approx O(n)≈O(n)
first指针走 (2x + y) 步,second指针走 (2x + 2y + x ) 步,总共走 (5x + 3y)步。因此基本上是 O(n)
空间复杂度:\approx O(1)≈O(1)
使用两个辅助变量first和second。