【LeetCode題解】142_環形連結串列2(Linked-List-Cycle-II)
阿新 • • 發佈:2018-11-06
目錄
描述
給定一個連結串列,返回連結串列開始入環的第一個節點。 如果連結串列無環,則返回 null
。
說明:不允許修改給定的連結串列。
進階:
你是否可以不用額外空間解決此題?
解法一:雜湊表
思路
最直接的解法就是利用一個集合儲存每次遍歷的節點的引用。之後,從連結串列頭開始遍歷,每遍歷一個節點,就判斷該節點的引用是否在集合中,如果不在集合中,則將該節點的引用放入集合中;如果在集合中,則返回該節點的引用(環的入口)。當然,如果能遍歷到連結串列尾部,此時連結串列無環,返回 null
Java 實現
/** * Definition for singly-linked list. * class ListNode { * int val; * ListNode next; * ListNode(int x) { * val = x; * next = null; * } * } */ import java.util.Set; import java.util.HashSet; public class Solution { public ListNode detectCycle(ListNode head) { ListNode curr = head; Set<ListNode> nodesSeen = new HashSet<>(); while (curr != null) { if (nodesSeen.contains(curr)) { return curr; } nodesSeen.add(curr); curr = curr.next; } return curr; } }
Python 實現
# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = None class Solution(object): def detectCycle(self, head): """ :type head: ListNode :rtype: ListNode """ curr = head nodes_seen = set() while curr: if curr in nodes_seen: return curr nodes_seen.add(curr) curr = curr.next return curr
複雜度分析
- 時間複雜度:\(O(n)\)
- 空間複雜度:\(O(n)\)
解法二:雙指標
思路
和 LeetCode 第 141 題一樣,如果不想佔用額外的空間的話,可以採用雙指標的方式。
假設連結串列的起始節點為 A,環的入口節點為 B,兩個指標(快慢指標)相交節點為 C,AB 兩點之間的長度為 \(x\),BC 兩點之間的長度為 \(y\),CB 兩點之間的長度為 \(z\)。慢指標 slow
走過的長度為 \(x+y\),快指標 fast
為了“趕上”慢指標,應該走過的長度為 \(x + y + z + y\),同時,由於快指標的速度是慢指標的兩倍,因此相同時間內,快指標走過的路程應該是慢指標(走過的路程)的兩倍,即
\[ x + y + z + y = 2 (x + y) \]
化簡得,
\[ x = z \]
因此,如果此時有另外一個慢指標 slow2
從起始節點 A 出發,則兩個慢指標會在節點 B (環的入口)相遇。
Java 實現
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
ListNode slow2 = head;
while (slow != slow2) {
slow = slow.next;
slow2 = slow2.next;
}
return slow;
}
}
return null;
}
}
// Runtime: 1 ms
// Your runtime beats 100.00 % of python submissions.
Python 實現
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
slow, fast = head, head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
slow2 = head
while slow != slow2:
slow = slow.next
slow2 = slow2.next
return slow
return None
# Runtime: 44 ms
# Your runtime beats 99.73 % of python submissions.
複雜度分析
- 時間複雜度:\(O(n)\),其中 \(n\) 表示連結串列的長度。最壞的情況下(連結串列有環),需要迭代的次數為 \(x + y + z = n\) 次,因此時間複雜度為 \(O(n)\)
- 空間複雜度:\(O(1)\),只需要儲存 3 個引用