數據結構與算法隨筆之鏈表-鏈表是否有環(二)

上一篇文章咱們分析了下鏈表之反轉單向鏈表,這篇文章咱們來分析下另一個關於鏈表的經典題目。java

判斷鏈表是否有環(在leetcode上的題目地址:環形鏈表)segmentfault

題目描述

給定一個鏈表,判斷鏈表中是否有環spa

解決方案

1、能夠使用hash表來實現,遍歷鏈表,每一個節點放入hash表中,若是hash表中包含了某個節點,那麼說明有重複節點存在,便是有環。若是沒環,那麼鏈表會遍歷結束。代碼以下:指針

public static <T extends Comparable<T>> boolean hasCycle1(Node<T> head) {
    HashSet<Node<T>> set = new HashSet<>();
    for(Node<T> n=head;n!=null;n=n.getNext()) {
        if(set.contains(n)) {
            return true;
        }
        set.add(n);
    }
    return false;
}
  • 備註Node類參照上篇文章

複雜度分析,假設鏈表長度爲ncode

  • 時間複雜度:每一個元素都要遍歷一遍,因此時間爲O(n),每次訪問hash表時間爲O(1)。
  • 空間複雜度:O(n),n個元素都會添加到hash表中。

2、上面這種方法能夠解決,可是須要藉助額外的空間複雜度,可否不使用額外空間解決此題呢?答案是有的,使用快慢指針,想象下,兩我的在一個環形跑道上賽跑,跑得快的必定會追上跑的慢的那我的吧。下面用圖示來展現下整個過程。leetcode

初始化時:rem

fast指針走兩步,slow指針走一步,不停遍歷的變化:get

最後快慢指針又相遇了,循環結束,代碼實現以下:hash

public static <T extends Comparable<T>> boolean hasCycle(Node<T> head) {
    if(head == null || head.getNext() == null) {
        return false;
    }
    Node<T> slow = head;
    Node<T> fast = head;
    while(fast != null && fast.getNext() != null) {
        slow = slow.getNext();
        fast = fast.getNext().getNext();
        if(slow == fast) {
            return true;
        }
    }
    return false;
}

複雜度分析,假設鏈表長度爲nit

  • 時間複雜度:O(n),鏈表無環時,快指針會先到達尾部,時間就是O(n);若是有環,那麼假設環部長度爲K,時間就是O(n+k),也就是O(n)
  • 空間複雜度:O(1)
相關文章
相關標籤/搜索