142. Linked List Cycle II
不定期更新leetcode解题java答案。
采用pick one的方式选择题目。
题意为给定单链表,如果链表存在循环回路则返回进入循环的开始节点,否则返回null。
易想到采用双指针的方式来判断是否单链表存在循环回路,具体方法是:将两个指针赋值为链表头,以不同速度向后遍历,如果两者可以相等,则有循环;否则为快速指针先进行到链表尾,不存在循环。
本题另外一点在于如何能找到循环回路的开始节点。试想假如存在回路,则满足如下关系:
m + n = l && m + n +s * k = 2 * l
上述式子的意义为:两个指针一个用单倍速度向后遍历,一个用双倍速度向后遍历,两者最后相遇在一起。m为进入循环前经过的节点数,n为进入循环后经过的节点数,l为慢速指针经过的总节点数,k为循环回路一个循环的节点数,s为正整数(未知)。
换句话说就是将两个指针的路程用我们可以添加的未知量加入进去。我们要得出的是m这个未知数,以通过链表头获取循环回路开始节点。
通过观察可得出: m + n + m = l + m = s * k + m
很显然,由两个指针节点相遇处再前进m个节点即可到达循环回路开始节点(总路程为m+s圈循环),而该点恰好为从链表头前进m个节点的位置。由此可以将快慢指针相遇处与链表头两个节点同时同速度向后遍历,相遇处即为所求。具体代码如下:
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 ListNode slow = head, fast = head; 15 int count = 0; 16 while(fast != null && fast.next != null){ 17 count++; 18 slow = slow.next; 19 fast = fast.next.next; 20 if(slow == fast) 21 break; 22 } 23 if(fast == null || fast.next == null) 24 return null; 25 26 slow = head; 27 for(int i = 0; i <= count; i++){ 28 if(slow == fast) 29 break; 30 fast = fast.next; 31 slow = slow.next; 32 } 33 return slow; 34 } 35 }