142. 環形連結串列 II

知識點:連結串列;set;快慢指標

題目描述

給定一個連結串列,判斷連結串列中是否有環。

給定一個連結串列,返回連結串列開始入環的第一個節點。 如果連結串列無環,則返回 null。

為了表示給定連結串列中的環,我們使用整數 pos 來表示連結串列尾連線到連結串列中的位置(索引從 0 開始)。 如果 pos 是 -1,則在該連結串列中沒有環。注意,pos 僅僅是用於標識環的情況,並不會作為引數傳遞到函式中。

說明:不允許修改給定的連結串列。

如果連結串列中存在環,則返回 true 。 否則,返回 false 。

進階:

你能用 O(1)(即,常量)記憶體解決此問題嗎?

示例
輸入:head = [3,2,0,-4], pos = 1
輸出:返回索引為 1 的連結串列節點
解釋:連結串列中有一個環,其尾部連線到第二個節點。 輸入:head = [1,2], pos = 0
輸出:返回索引為 0 的連結串列節點
解釋:連結串列中有一個環,其尾部連線到第一個節點。 輸入:head = [1], pos = -1
輸出:返回 null
解釋:連結串列中沒有環。

解法一:集合

利於集合不重複的特性,依次將節點存入集合;

/**
* 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) {
Set<ListNode> set = new HashSet<>();
while(head != null){
if(set.contains(head)){
return head;
}
set.add(head);
head = head.next;
}
return null;
}
}

時間複雜度:O(N);

空間複雜度:O(N);

解法二:快慢指標

和141題一樣,想一下,快指標每次走兩步,慢指標每次走一步,如果設快指標走的路程是f,慢指標走的路程是s,那在相遇的時候,快指標正好是慢指標的兩倍:f=2s;此外相遇時,快指標比慢指標多走了n圈,即f = s + nb, b 是一圈的長度,即得到這兩個式子:

    1. f = 2s;
    1. f = s + nb;

推出;s = nb;

走a+nb步一定是在連結串列入環口,slow已經走了nb了,再走a就可以了,怎麼走a呢,讓一個指標從頭走,最後就可以在起點處相遇;

/**
* 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 fast = head;
ListNode slow = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
fast = head;
while(fast != slow){
fast = fast.next;
slow = slow.next;
}
return fast;
}
}
return null;
}
}

時間複雜度:O(N);

空間複雜度:O(1);

體會

雙指標是一種很常用很常用的解題思路,其中有快慢指標這種,就是用來解決環、迴圈的問題;就是一個追及問題。