一个链表中包含环,请找出该链表的环的入口结点。
这个题目leetcode上做到过,当时的思路是先找到快慢指针的第一次交点。然后把其中一个指针放回头部,两者以相同速度前进,相遇点即是入口,这需要数学证明,不大容易想
该方法代码如下
public ListNode EntryNodeOfLoop(ListNode pHead){
ListNode slow = pHead;
ListNode fast = pHead;
while(slow != null && fast !=null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
if(slow == fast) break;
}
if(fast == null || fast.next == null) return null;
slow = pHead;
while(slow != fast){
slow = slow.next;
fast = fast.next;
}
return slow;
}
这次又多了两种新思路:
这种方法会破坏链表的结构,但想法的确很不错:
/*
时间复杂度为O(n),两个指针,一个在前面,另一个紧邻着这个指针,在后面。
两个指针同时向前移动,每移动一次,前面的指针的next指向NULL。
也就是说:访问过的节点都断开,最后到达的那个节点一定是尾节点的下一个,
也就是循环的第一个。
这时候已经是第二次访问循环的第一节点了,第一次访问的时候我们已经让它指向了NULL,
所以到这结束。
*/
public ListNode EntryNodeOfLoop2(ListNode pHead){
if(pHead == null) return pHead;
ListNode pre = pHead;
ListNode cur = pHead.next;
while(cur != null){
if(pre.next == null) return pre;
ListNode tmp = cur;
cur = cur.next;
pre.next = null;
pre = cur;
}
return null;
}
其实还有一种比较常规的想法
如果链表中环 有n个结点,指针P1在链表上向前移动n步,然后两个指针以相同的速度向前移动。
当第二个指针指向环的入口结点时,第一个指针已经围绕着环走了一圈又回到了入口结点。
所以首先要得到环中结点的数目。
这个代码就不写了