[路飞]_每天刷leetcode_23(环路检测 Linked List Cycle)

259 阅读3分钟

环路检测

LeetCode传送门面试题 02.08. Linked List Cycle LCCI

题目

给定一个链表,如果它是有环链表,实现一个算法返回环路的开头节点。若环不存在,请返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

Given a circular linked list, implement an algorithm that returns the node at the beginning of the loop.

Circular linked list: A (corrupt) linked list in which a node's next pointer points to an earlier node, so as to make a loop in the linked list.

Example:

Input: head = [3,2,0,-4], pos = 1
Output: tail connects to node index 1

Input: head = [1,2], pos = 0
Output: tail connects to node index 0

Input: head = [1], pos = -1
Output: no cycle

Follow Up: Can you solve it without using additional space?


思考线


解题思路

####方法一

ES6 新增了 Map对象,一个 Map的键可以是任意值,包括函数、对象或任意基本类型。那么我们可以循环一下这个链表,然后让每个节点都存储在Map中,且每次循环开始时检测一下Map是否已经保存该节点的值,若已经保存,则说明存在环,且该节点就是环路的开头结点。

实现代码如下

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var detectCycle = function(head) {
    const hashMap = new Map();
    let f = head;
    while(!hashMap.get(f)) {
        if(!f) return null;
        hashMap.set(f, f);
        f = f.next;
    }
    return f;
    
};

方法二

在判断是否有环的题里面,我们可以使用快慢指针法来解答,但是快慢指针只能确定是否存在环却不能确定环的起始位置,那么我们确定存在环以后如何确定环起始位置就是通过快慢指针法来解题的关键了。

现在我们假设 head 到 环的起始位置距离为a,环起始位置到相遇位置距离为b,b又到相遇位置的距离为c.由于我们使用快慢指针(指针都从head出发,快指针每次走两步,慢指针每次走一步)。

当相遇时,则有关系(a + b)* 2 = a + n(b+c) + b 化简可得 a = (n-1)(b+c) +c,由于b+c是一个环的距离,所以 a = c

那么我们只要在设一个变量findStart = head,然后让 相遇点和 findStart 一同往下走,则相遇点就是环的起始点!!!

得到这个规律那么我们的代码就好实现了

代码如下

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var detectCycle = function(head) {
    let slow, fast;
    slow = fast = head;
    while(fast) {
        if(!fast.next) return null
        fast = fast.next.next;
        slow = slow.next;
        if(slow === fast) {
            // 有环
            let findStart = head;
            while(findStart !== slow) {
                findStart = findStart.next;
                slow = slow.next;
            }
            return findStart
        }
    }
    return null;
};

这就是我对本题的解法,如果有疑问或者更好的解答方式,欢迎留言互动。