前面,我們實現了連結串列的 反轉 操作,本篇來聊聊,如何檢測單連結串列中的環。
連結串列環檢測
有兩種方法來解決這個問題:
使用Hashing
思路
定義一個Map,當迴圈遍歷Linked List時,依次將Node放入Map中,等到迴圈到下一輪時,檢查Node是否存在於Map中,若存在則表示有環存在。
實現
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
Map map = new IdentityHashMap();
for(ListNode x = head; x != null;){
if(map.containsKey(x)){
return true;
}
map.put(x, null);
x = x.next;
}
return false;
}
}
複製程式碼
Floyd判圈演算法
如果有限狀態機、迭代函式或者連結串列上存在環,那麼在某個環上以不同速度前進的2個指標必定會在某個時刻相遇。同時顯然地,如果從同一個起點(即使這個起點不在某個環上)同時開始以不同速度前進的2個指標最終相遇,那麼可以判定存在一個環,且可以求出2者相遇處所在的環的起點與長度。
從Linked List的Head節點出發,我們定義兩個移動指標,一個的移動速度為每次前進一個節點,另一個每次前進兩個節點。然後判斷這兩個指標移動後的結果是否相等。
程式碼
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
if(slow == fast){
return true;
}
}
return false;
}
}
複製程式碼
這兩種方式的時間複雜度均為O(n),空間複雜度均為O(1).