142. 环形链表 II|刷题打卡

178 阅读3分钟

一、题目描述

二、解题思路

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

/**
 * @param {ListNode} head
 * @return {ListNode}
 * 思考,就可以直接使用哈希表进行解决
 * 执行用时:88 ms, 在所有 JavaScript 提交中击败了92.47%的用户
 * 内存消耗:41 MB, 在所有 JavaScript 提交中击败了8.17%的用户
 */
// var detectCycle = function(head) {
//     let map = new Map();
//     while (head) {
//         if (map.has(head)) {
//             return map.get(head);
//         }
//         map.set(head, head);
//         head = head.next;
//     }

//     return head;
// };

/**
 * 方案二,采用双指针的形式,
 * 思路一样,如果之前节点找到了这个节点,就直接返回
 * 目前这个版本,超出时间限制,
 * 如果是尾链表形成环的话,那么其实快指针比慢指针多走一步。快指针第一次重复的点就是入环点,对于哈希表是这样的。
 * 如果是双指针呢。快指针先到到入环点,经过,慢指针后到入环点。每次都是都走一步,所以这个版本永远不会相逢,所以会超出时间限制。
 */

// 这个版本可以判断是否可以追上,并且得到追上的节点,但是这个节点不是入环的节点。
// var detectCycle = function (head) {
//     if (!head || head.next === null) return null;
//     let slow = head;
//     let fast = head.next;

//     while (fast && fast.next) {
//         if (fast === slow) {
//             return slow;
//         }
//         slow = slow.next;
//         fast = fast.next.next;
//     }

//     return null;
// }
/**
 * 参考:https://leetcode-cn.com/problems/linked-list-cycle-ii/solution/huan-xing-lian-biao-ii-by-leetcode-solution/ 题解
 * 继续深入,如何寻找到入环的节点。两个节点同时从起点开始走
 * 1. 快针走的是慢针的两倍。
 * 2. 因为慢针走过的路,快针已经走过一遍;
 * 3. 快针走过的剩余路程,也就是和慢针走过的全部路程相等。(a+b = c+b)
 * 4. 刨去快针追赶慢针的半圈(b),剩余路程即为所求入环距离(a=c)
 * 所以当他们相遇的时候,这时候,这时候声明一个新的指针从 head 开始走,当它和慢指针相遇的时候,就是他们相遇的节点。
执行用时:96 ms, 在所有 JavaScript 提交中击败了66.71%的用户
内存消耗:40.1 MB, 在所有 JavaScript 提交中击败了90.07%的用户
 */
var detectCycle = function (head) {
    if (head === null) return null;
    let slow = head;
    let fast = head;

    while (fast !== null) {
        slow = slow.next;
        if (fast.next !== null) {
            fast = fast.next.next;
        } else {
            return null;
        }

        if (fast === slow) {
            let ptr = head;
            while (ptr !== slow) {
                ptr = ptr.next;
                slow = slow.next;
            }
            return ptr;
        }
    }

    return null;
}

思路

  1. 首先快慢指针都从起点出发,慢指针每次走一格,快指针每次走两格。
  2. 快针是慢针走的两倍,因为慢针走的路,快针已经走过一遍。
  3. 快针走过的剩余路程,也就是和慢针走过的全部路程相等。(a+b = c+b);
  4. 刨去快针追赶慢针的半圈(b),剩余路程即为所求入环距离(a=c),当他们相遇了,从起点在走一格指针,当它和慢针相遇的时候,就是入环点。

三、总结

  1. 这道题花了自己一个小时理解清楚,最开始能够快速的通过哈希表完成,但是就是双指针的追逐理解了一会儿。
  2. 双指针的关键点,当他们追上了,如何去计算出入环的节点。用到数学的相关推理知识。
  3. 当理解了整个过程之后,代码就好写了。