[路飞]_LeetCode题142环形链表II

205 阅读1分钟

题目描述

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

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

示例 1:

circularlinkedlist.png

输入: head = [3,2,0,-4], pos = 1
输出: 返回索引为 1 的链表节点
解释: 链表中有一个环,其尾部连接到第二个节点。

示例 2:

circularlinkedlist_test2.png

输入: head = [1,2], pos = 0
输出: 返回索引为 0 的链表节点
解释: 链表中有一个环,其尾部连接到第一个节点。

示例 3:

circularlinkedlist_test3.png

输入: head = [1], pos = -1
输出: 返回 null
解释: 链表中没有环。

  提示:

链表中节点的数目范围是 [0, 10410^4]
1/1051/10^5 <= Node.val <= 10510^5
pos 为 -1 或者链表中的一个有效索引 。

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/li… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

数学思想:

假定有一个环形链表,如图

image.png

有两个指针起始均指向链表头部,慢指针每次位移量为1,快指针每次位移量为2,图中位移量A为快慢指针共同移动的路程,设为A,快慢指针,某一时刻在45处相遇,此时快慢指针共同经过的路程设为B,从相遇点到入环点的路程设为C,此时慢指针走过的距离为A+B,快指针走过的短距离为A+n(B+C)+B,n为快慢指针相遇时快指针多跑的圈数, 因为快指针速度是慢指针的两倍,所以产生等式:2(A+B)=A+n(B+C)+B变形为:A=(N-1)(B+C)+C,我们知道B+C的含义为一圈,一圈的位移量是0,于是等式变为A=(N-1)×0+C 推出A=C所以,当我们从相遇点开始走,让第三个指针同时从链表头开始走,当两个指针相遇就是链表的入环点

解题方案:定义两个指针,初始均指向链表头地址,快指针每次移动两个位移量,慢指针每次移动一个位移量,如果存在指针指向null则结束循环返回false(链表非闭合),如果两个指针存在相等的时候,则说明链表为闭合链表,此时定义第三个指针指向链表头部,同时开始位移,直到相等,相等值即为链表的入环处

解题代码:

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

/**
 * @param {ListNode} head 链表头指针
 * @return {ListNode}
 */

var detectCycle = function(head) {
    //头指针为空==>链表非环形链表
    if(!head) return null;

    let pre = head;//慢指针
    let cur = head;//快指针

    //如果当前位置或下一个位置指向空,即链表有终点==>非环形链表
    while(cur && cur.next){

      pre = pre.next;//慢指针走一步
      cur = cur.next.next;//快指针走两步

      //当两个指针相等说明指针相遇==>链表为环形链表
      if(pre === cur){
        //定义头结点
        let res = head;
        
        //让头结点与当前指针节点同时移动一个单位
        //当二者相等即指针相遇即为环形链表的入环处
        //跳出循环返回当前指针位置
        while(res !== cur){
          res = res.next;
          cur = cur.next;
        };
        return res;
      }
    };
    return null;
};