链表有环无环的判断以及环的第一个节点的检测问题。编程之美上面也有。
思路极为简单:
1. 是否有环,通过快、慢两个指针从头一直走,快的每次走两步,慢的每次走一步,如果快的最后有遇到null,说明没有环;如果快的最后和慢的同时走到某个节点,则说明有环。
2. 环的第一个节点,用两个指针,一个从链表的头部开始,一个从快慢两个指针的同时指向的那个节点开始,每次走一步,当这两个指针同时到达一个节点A时,A就是这个环的第一个节点,这是有个数学关系在里头,可以自行推倒。
下面是已AC代码。
1 /** 2 * detect the first node of the cycle if it has cycle 3 * @param head 4 * @return the first node or null 5 */ 6 public ListNode detectCycle(ListNode head) 7 { 8 if(head == null || head.next == null) 9 return null; 10 11 //use a faster pointer and a slower pointer, to find the coincident node; 12 ListNode faster = head; 13 ListNode slower = head; 14 ListNode con = null; 15 while(faster!=null && faster.next!=null) 16 { 17 faster = faster.next.next; 18 slower = slower.next; 19 if(faster == slower) 20 { 21 con = faster; 22 slower = head; 23 break; 24 } 25 } 26 //if there is no cycle, directly return null 27 if(con == null) 28 return null; 29 30 //find the first node of the cycle, the one that both reached at the same time 31 while(slower!=faster) 32 { 33 slower = slower.next; 34 faster = faster.next; 35 } 36 37 return faster; 38 } 39 /** 40 * determine if it has a cycle in it 41 * @param head 42 * @return 43 */ 44 public boolean hasCycle(ListNode head){ 45 if(head == null || head.next == null) 46 return false; 47 48 //use a faster pointer and a slower pointer, to find whether they are coincident in one node; 49 ListNode faster = head; 50 ListNode slower = head; 51 52 while(faster!=null && faster.next!=null) 53 { 54 faster = faster.next.next; 55 slower = slower.next; 56 if(faster == slower) 57 return true; 58 } 59 return false; 60 }