Given a linked list, return the node where the cycle begins. If there is no cycle, return null
.
Note: Do not modify the linked list.
Follow up:
Can you solve it without using extra space?
题意:给定一个链表,判断链表的环的起点,如果没有则返回null
解题思路:(1)用快慢指针的方法判断链表是否有环,如果有,求出快慢指针第一次相遇的节点。
(2)从相遇节点之后把原链表分成两个部分,把问题转化为求两个链表相交的第一个节点
/**
* 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 || head.next == null || head.next.next == null) {
return null;
}
ListNode fast = head;
ListNode slow = head;
ListNode head1 = head;
ListNode head2 = null;
//求出快慢指针第一次相遇的节点
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow ) {
//确定第二个链表的表头。并将原链表相遇节点指向null
head2 = slow.next;
slow.next = null;break;
}
}
if (fast != slow) {
return null;
}
//问题转化为求两个链表的相交部分的第一个节点
ListNode curNode1 = head1;
ListNode curNode2 = head2;
int length1 = 1, length2 = 1;
while (curNode1.next != null) {
length1++;
curNode1 = curNode1.next;
}
while (curNode2.next != null) {
length2++;
curNode2 = curNode2.next;
}
curNode1 = head1;
curNode2 = head2;
int count = Math.abs(length1 - length2);
if (length1 >= length2) {
while (count > 0) {
curNode1 = curNode1.next;
count--;
}
}else {
while (count > 0) {
curNode2 = curNode2.next;
count--;
}
}
while (curNode1 != curNode2) {
curNode1 = curNode1.next;
curNode2 = curNode2.next;
}
return curNode1;
}
}
第二个思路:这个方法比上面的方法运行时间快
入下图,第一次相遇时slow走过的距离为a+b,fast走过的距离为a+b+c+b。
因为fast的速度是slow的两倍,所以fast走的距离是slow的两倍,有 2(a+b) = a+b+c+b,可以得到a=c。
也就是从head到环开始的路程 = 从相遇节点到环开始的路程
那么,只要Slow和Fast相遇了,就拿一个从头开始走,一个从相遇的节点开始走
两个都走一步,那么再次相遇必定是环的开始节点
/**
* 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 || head.next == null || head.next.next == null) {
return null;
}
ListNode fast = head;
ListNode slow = head;
ListNode head1 = head;
ListNode head2 = head;
//求出快慢指针第一次相遇的节点
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow ) {
head2 = slow;
break;
}
}
if (fast != slow) {
return null;
}
while (head1 != head2) {
head1 = head1.next;
head2 = head2.next;
}
return head1;
}
}