面试算法之:如何判断链表是否有环

方法一:双重循序遍历

从头节点开始,一次遍历单链表的,每一个人节点。没遍历一个新节点,就从头检查新节点之前的所有节点,用新节点和之前所有的节点一次比较,如果发现和之前的某一个节点相同 ,则说明该节点被遍历两次,说明环。
缺点:时间复杂度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 //有环
        }
    }
}

拓展之:如何求出入环点?和 环的长度?

欢迎在下方评论

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