Leetcode 142. 环形链表II(Linked list cycle ii)

发布时间 2023-08-19 12:30:17作者: Ahci

题目链接

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

如果链表中有某个节点, 可以通过连续跟踪next指针再次到达, 则链表中存在环. 为了表示给定链表中的环, 评测系统内部使用整数pos来表示链表尾连接到链表中的位置(索引从 0 开始). 如果pos是-1, 则在该链表中没有环.

注意: pos不作为参数进行传递, 仅仅是为了标识链表的实际情况. 不允许修改链表。

示例 1:

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

示例 2:

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

提示:

  • 链表中节点的数目范围在范围 [0, 104] 内
  • -105 <= Node.val <= 105
  • pos 的值为 -1 或者链表中的一个有效索引

思路

这道题首先想到的方法是使用Set去重来判断是否有环以及环的入口在哪个位置.

第二种方法是双指针法(快慢指针), 设置两个指针(slow and fast), slow指针每次前进一个节点, fast指针每次前进两个节点, 只要链表中有环, 它们就一定会相遇.

在这道题中的问题是如何确定环的入口. 可以将链表分为三个部分, 分别是从头节点到环入口的节点数x, 从环入口到fast指针和slow指针相遇的节点数为y, 从相遇节点到环入口的节点数z.

这样相遇时, slow指针走过的节点数为x + y, fast指针走过的节点数为x + y + n(y + z), 这里的n指的是fast指针走了n圈才遇到slow指针, (y + z)表示一个圈内的节点数.

由于fast一次走两个节点, slow一次走一个节点, 所以fast走过的节点数 == slow走过的节点数 * 2

也就是: (x + y) * 2 = x + y + n(y + z), 简化后为x = n(y + z) - y, 最后得到x = (n - 1) * (y + z) + z

由于fast至少走一圈才可以遇到slow指针, 所以n必定大于等于1. 当n == 1时, 公式化简为x = z

也就是从头节点出发一个指针, 从相遇节点出发一个指针, 两指针每次走一个节点, 相遇处即为环形入口节点.

代码实现

HashSet:

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head == null) {
            return null;
        }

        ListNode temp = head;
        Set<ListNode> set = new HashSet<ListNode>();

        while(temp != null) {
            if(set.contains(temp)) {
                return temp;
            } else {
                set.add(temp);
            }
            temp = temp.next;
        }

        return null;
    }
}

快慢指针:

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;

        while(fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;

            if(slow == fast) {
                ListNode tempNode1 = fast;
                ListNode tempNode2 = head;

                while(tempNode1 != tempNode2) {
                    tempNode1 = tempNode1.next;
                    tempNode2 = tempNode2.next;
                }

                return tempNode1;
            }
        }

        return null;
    }
}