題目描述
給定一個鏈表,返回鏈表開始入環的第一個節點。如果鏈表無環,則返回 null。
爲了表示給定鏈表中的環,我們使用整數 pos 來表示鏈表尾連接到鏈表中的位置(索引從 0 開始)。 如果 pos 是 -1,則在該鏈表中沒有環。
說明:不允許修改給定的鏈表。
示例 1:
輸入:head = [3,2,0,-4], pos = 1
輸出:tail connects to node index 1
解釋:鏈表中有一個環,其尾部連接到第二個節點。
示例 2:
輸入:head = [1,2], pos = 0
輸出:tail connects to node index 0
解釋:鏈表中有一個環,其尾部連接到第一個節點。
題目解析
方法一:哈希表
解題思路
首先可以想到的方法就是遍歷鏈表並將遍歷的鏈表Node節點存入哈希表中,若鏈表有環則返回第一個出現的重複的Node節點。
代碼示例
Java:
/*
* Definition for singly-linked list.
*/
public class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
public ListNode detectCycle(ListNode head) {
Set<ListNode> visited = new HashSet<ListNode>();
ListNode curr = head;
while (curr != null) {
if (visited.contains(curr)) {
return curr;
}
visited.add(curr);
curr = curr.next;
}
return null;
}
複雜度分析
時間複雜度:O(n)
空間複雜度:O(n),通過額外空間存儲遍歷節點
方法二:雙指針
解題思路
在上一題環形鏈表中已經提過若鏈表有環的情況,快慢指針會在某個節點相遇。
此時鏈表頭節點到環起始點的距離爲x,環起始點到快慢指針相遇節點的距離爲y,然後相遇節點再繼續走z的距離回到環起始點。
由於快指針的速度時慢指針的兩倍,所以快指針追上慢指針必然比慢指針多走一圈。此時慢指針走的路程s = x + y,快指針走的路程f = x + y + z + y,且 f = 2s,所有可以得到 x = z,也就是說頭節點到環起始點的距離等於指針相遇節點到環起始點距離。所以當快慢指針相遇時,指定其中一個指針回到頭節點,並保持相等的速度繼續遍歷直到兩個指針再次相遇則爲鏈表環的起始點了。
代碼示例
Java:
/*
* Definition for singly-linked list.
*/
public class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
public ListNode detectCycle(ListNode head) {
ListNode slow = head, fast = head;
while (true) {
if (fast == null || fast.next == null) {
return null;
}
slow = slow.next;
fast = fast.next.next;
if (slow == fast) break;
}
fast = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return fast;
}
複雜度分析
時間複雜度:O(n)
空間複雜度:O(1)