方法一:双重循序遍历
从头节点开始,一次遍历单链表的,每一个人节点。没遍历一个新节点,就从头检查新节点之前的所有节点,用新节点和之前所有的节点一次比较,如果发现和之前的某一个节点相同 ,则说明该节点被遍历两次,说明环。
缺点:时间复杂度O(n^2)太高,空间复杂度O(1)
代码如下
///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 //有环
}
}
}
拓展之:如何求出入环点?和 环的长度?
欢迎在下方评论