双指针龟兔赛跑判断链表是否成环

806 阅读1分钟

给定一个链表,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。

如果链表中存在环,则返回 true 。 否则,返回 false 。

image.png

方法一:数组缓存

判断链表是否成环,最主要的依据就是在遍历的同时会回到某个已经经历过的节点。可通过将遍历的节点存放在数组中,在便利的同时判断其是否在数组中存在即可。若链表遍历至 null 那么这个链表必定不成环。

代码:

var hasCycle = function(head) {
    if (head === null || head.next === null) {
        return false
    }
    let list = []
    while(head) {
        if (list.indexOf(head) !== -1) {
            return true
        }
        list.push(head)
        head = head.next
    }
    return false
};

方法二:双指针-龟兔赛跑

链表如果存在环,那么这个链表遍历一定是无穷的。如果使用双指针,分别控制指针移动的快慢,那么这两个指针一定会相交!类似于故事中的龟兔赛跑。

图解:

image.png

假设存在这样的环形链表

分别在root定义两个指针,代表兔子和乌龟。

兔子和乌龟同时出发,开始遍历,兔子的速度快,每次遍历2格,乌龟的速度慢,每次遍历1格。

如图:

ScreenRecorderProject4.gif

代码实现:

var hasCycle = function(head) {
    let slow = head
    let quick = head
    while(quick && quick.next !== null && quick.next.next !== null) {
        quick = quick.next.next
        slow = slow.next
        if (quick === slow) {
            return true
        }
    }
    return false
}