给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。
说明:不允许修改给定的链表。
进阶:
你是否可以使用 O(1) 空间解决此题?
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/linked-list-cycle-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
分析:
f s 记录快慢指针FS的步数 F指针一次走2步 S指针一次1步 f=2s
F S在环内相遇时 f = s+nb b:环的长度,n:F比S多走的圈数,未知,但可以证明是1,即慢指针第一圈必见到快指针
得 s = nb ,所以 f = 2nb
设 a为头指针走到入环点的步数,步数k为入环后走到(回)入环点的步数 k=a+nb
此时s=nb,所以k= s+a ,S再走a步就可以走到(回)到入环点 而此时从头节点出发走a步也能到入环点(第一次)H.next(a) = S.next(a)
所以此时从head出发的 H指针 经过 a步 将会在入环点和 S指针相遇
通过比较H S指针所在节点是否相等就能得到入环点了
fast快指针节点,一次走二步(跳两节点,.next.next),slow慢指针节点,一次走一步(跳一个节点,.next)
public static ListNode findEnterCircleNode(ListNode head){
ListNode fast = head, slow = head;
while (true) {
//如果当前节点为空或者下一节点为空(说明走到尾结点了),不存在环
if (fast == null || fast.next == null) return null;
fast = fast.next.next;
slow = slow.next;
if (fast == slow) break;//两指针相遇,记下slow节点(位置)
}
fast = head;//head,slow开始同步走,直到在入环点相遇得入环点
//这里弄个count=0,count++就是求a是几步的过程
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return fast;
}
public static void main(String[] args) {
ListNode node1 = new ListNode(3);
ListNode node2 = new ListNode(2);
ListNode node3 = new ListNode(0);
ListNode node4 = new ListNode(4);
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node2;
System.out.println(findEnterCircleNode(node1).val);
}
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}