力扣142(Java)-环形链表Ⅱ(中等)
题目:
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
示例3:
输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。
提示:
- 链表中节点的数目范围在范围 [0, 104] 内
- -105 <= Node.val <= 105
- pos 的值为 -1 或者链表中的一个有效索引
进阶:你是否可以使用 O(1) 空间解决此题?
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/linked-list-cycle-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
本题的重点在两个方面:
1.判断是否有环:
与 力扣141.环形链表 解题思路一致,运用快慢指针:
- 定义两个指针slow 和 fast,从头结点出发,使fast每次走两步,slow每次走一步;
- 如果存在环,那快慢指针一定是在环中相遇,因为fast一定先进入环中,相对于slow来说,fast是以每次移动一个结点的速度来慢慢靠近slow的,要相遇一定是在环中相遇;
- 移动的过程中,循环条件是:fast != null && fast.next != null,如果fast == slow 说明相遇了,则存在环,否则不存在。
2.计算入环的节点位置:
会存在等式,快慢指针相遇时: 2 * (x + y) = n * (y +z) + x + y == > x = (n-1)(y+z) + z,需要注意,慢指针在绕环的第一圈时肯定会与快指针相遇。
- n = 1 时, x = z,相遇的点是环形的入口点
- n >= 1时,说明快指针在绕了n-1圈以后,在绕第n圈的时候绕了z距离与慢指针相遇了,相遇的点还是环形的入口点
这时设置第一个位置指针为inde1指向头节点,即index1 = head, 第二个位置指针index2指向相遇的节点 index2 = slow (这时候相遇了指向fast也可以),开始循环,循环条件是 index1 != index2:
- 循环内,每次移动一步index1和index2,直到index1 = index2,找到入环点,返回index1 (index2也行);
- 整个链表遍历完以后,无环,直接返回null。
代码:
1 /** 2 * Definition for singly-linked list. 3 * class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int x) { 7 * val = x; 8 * next = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 public ListNode detectCycle(ListNode head) { 14 if (head == null || head.next == null) return null; 15 //先判断是否有环--快慢指针 16 ListNode fast = head, slow = head; 17 while (fast != null && fast.next != null){ 18 fast = fast.next.next; 19 slow = slow.next; 20 //当存在环时找交点即入环点 21 while (fast == slow){ 22 ListNode index1 = head; 23 ListNode index2 = slow; 24 while (index1 != index2){ 25 index1 = index1.next; 26 index2 = index2.next; 27 } 28 return index1; 29 } 30 } 31 return null; 32 } 33 }