面試算法之:如何判斷鏈表是否有環

方法一:雙重循序遍歷

從頭節點開始,一次遍歷單鏈表的,每一個人節點。沒遍歷一個新節點,就從頭檢查新節點之前的所有節點,用新節點和之前所有的節點一次比較,如果發現和之前的某一個節點相同 ,則說明該節點被遍歷兩次,說明環。
缺點:時間複雜度O(n^2)太高,空間複雜度O(1)

代碼如下

0
1
2
3
4
5
///Swift 鏈表
public class Node {
    var data: Int
    var next: Node?
    init(_ data: Int) {
        self.data = data;
    }
}

func nodeIsRing(_ node: Node) -> Bool {
    var nextNode = node.next
    while nextNode != nil {
        var proNode = node
        while (nextNode! !== proNode) {
            if proNode === nextNode?.next {
                return true //有相等的就返回true  有環啦
            }
            proNode = proNode.next!
        }
        nextNode = nextNode?.next//繼續遍歷下一個
    }
    return false;
}

方法二:把之前的遍歷的結果實現存儲起來

前邊遍歷的數據都存儲起來,新的節點和之前的對比,如果有相同的這說明就是有環。可以用哈希表,代碼略…
時間複雜度:O(n) 空間複雜度也是O(n)

方法三:如果環形跑道,速度不同時,兩個人一定會相遇。

既然是環,我們用兩個變量,一個增幅是1,一個增幅是二,那麼兩個指針必然會相遇。如果不是環,永遠也不會相遇。

時間複雜度:O(n) 空間複雜度也是O(1)

代碼

func isNodeSpeed(_ node: Node) -> Bool {
    var fastNode: Node? = node
    var slowNode: Node? = node
    while true {
        fastNode = fastNode?.next?.next
        slowNode = slowNode?.next
        if fastNode == nil && slowNode == nil {
            return false  //不是環
        }
        if fastNode != nil && slowNode != nil && fastNode === slowNode {
            return true //有環
        }
    }
}

拓展之:如何求出入環點?和 環的長度?

歡迎在下方評論

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章