链表中环的入口节点
题目
- 如果一个链表中包含环,如何找出环的入口节点?
解题分析:
- 第一步:判断链表中是否有环。
设置连个指针同时指向头节点,一个指针每次走两步,一个指针每次走一步,如果存在环,则两个指针一定可以相遇,相遇的节点一定是环内的某一点。 - 第二步:确定环中节点数目。
从第一步中可以得到环中的一个节点,设置一个指针指向这个节点,遍历环一次,统计出有多少个节点。 - 第三步:找出环的入口
因为环的长度已知了(设为k),那么就是知道了入口所在的位置(倒数的位置),可以参考上一题的思想链表中倒数第k个节点,设置两个指针指向头结点,先让一个指针走k步,然后两个指针一起走。与上一题不同之处在于,我们不需要判断是否到达了链表尾部,只需考虑两个指针是否指向了同一个对象即可。
代码:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
ListNode aNodeInLoop = IsLoop(pHead);
int numInLoop = 0;
if(aNodeInLoop == null) {
return null;
}
else {
numInLoop = NumNodeInLoop(aNodeInLoop);
}
ListNode first = pHead;
ListNode second = pHead;
while(numInLoop > 0) {
first = first.next;
numInLoop--;
}
while(first != second){
first = first.next;
second = second.next;
}
return first;
}
//判断是否有环,如果有,返回两个指针相遇的节点,否则返回null
public ListNode IsLoop(ListNode pHead) {
if(pHead == null) {
return null;
}
ListNode slow = pHead.next;
if(slow == null) {
return null;
}
ListNode fast = pHead.next.next;
if(fast == null) {
return null;
}
while(slow != null && fast != null) {
if(slow.equals(fast)) {
return slow;
}
slow = slow.next;
fast = fast.next;
if(fast != null) {
fast = fast.next;
}
}
return null;
}
//环中的节点数目
public int NumNodeInLoop(ListNode pHead) {
ListNode temp = pHead.next;
int res = 1;
while(temp != pHead) {
temp = temp.next;
res++;
}
return res;
}
}