题目描述
对于一个给定的链表,返回环的入口节点,如果没有环,返回null
拓展:
你能给出不利用额外空间的解法么?
牛客上的一个题目,判断是否有环,使用快慢指针即可,要找到环的入口就需要再分析一下
方法一:
因为快指针的速度是慢指针的2倍,所以当快慢指针第一次相遇时,快指针走过的路程(暂时就这么叫)是慢指针的2倍
所以可以得出如下等式:假设快慢指针相遇时,快指针已经绕了n圈
2(x+y)=x+y+n*(y+z)
整理一下可得
x=(n-1)(y+z)+z
可以发现y+z恰好是环的一圈,x等于n-1圈环加z,所以第一次相遇后慢指针回到起点,快慢指针以相同的速度向前走(一次走一格),
当慢指针走了x长的路程时,快指针绕了n-1圈并且还走了z,这时他们恰好相遇在入口(真巧)
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){ 15 return null; 16 } 17 ListNode slow = head; 18 ListNode fast = head; 19 while(fast != null && fast.next != null){ 20 fast = fast.next.next; 21 slow = slow.next; 22 if(fast == slow){ 23 break; 24 } 25 } 26 if(fast == null || fast.next == null){ 27 return null; 28 } 29 slow = head; 30 while(slow != fast){ 31 slow = slow.next; 32 fast = fast.next; 33 } 34 return slow; 35 } 36 }
方法二(可先看代码):
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){ 15 return null; 16 } 17 ListNode slow = head,fast = head.next; 18 ListNode t = head.next; 19 while(slow != fast){ 20 if(fast == null || fast.next == null){ 21 return null; 22 } 23 slow = slow.next; 24 fast = fast.next.next; 25 if(slow == fast)//这里必须加判断,否则会出现空指针异常 26 t = fast.next; 27 } 28 29 slow = head; 30 while(slow != t ){ 31 slow = slow.next; 32 t = t.next; 33 } 34 return slow; 35 } 36 }
方法二是看了leetcode141的题解才有的想法,但是没有方法一,直接方法二就有点困难。我觉得方法二有点鸡肋