链表问题11——两个单链表相交的系列问题(一):找到有环链表的环入口节点

题目

判断一个链表是否有环,如果有,则返回第一个进入环的节点,没有则返回null。


思路

如果一个链表没有环,那么遍历链表一定可以遇到链表的终点;如果链表有环,那么遍历链表就永远在环里转下去了。如何找到第一个入环节点,具体过程如下:

  1. 设置一个慢指针slow和一个快指针fast。slow每次走一步,fast每次走两步,遍历链表。
  2. 如果链表无环,fast一定会先到终点,并返回null。
  3. 如果有环,fast指针和slow指针会在环中某个位置相遇;此时,fast指针重新回到head位置,slow指针不动。接下来,fast指针每次从移动两步变成移动一步,slow指针依然每次移动一步,然后继续遍历。
  4. fast指针和slow指针一定会在入环的节点处相遇。

证明:

  • 假设该链表总长度为N个节点,从头节点到入口节点有M个节点,环长L个节点
  • 假设第一次相遇时,slow走了k个节点,2k-k=x*L,解释一下,fast走了2k个节点,他们要在环中相遇,fast要比slow多走了x圈,一圈长为L个节点
  • 那么从当前的的相遇的k节点走到入口节点需要多少步呢?L-\left ( k \right -M)=L-k+M=L-x*L+M=(1-x)*L+M
  • 从上式我们可以推断从当前节点走到入口节点需要转(1-x)圈再走M步,那么此时让fast从头节点开始一步一步走M步,下一次的相遇就是在入口处的节点。

源码

public class Node{
	public int value;
	public Node next;
	public Node(int data){
		this.value=data;
	} 
}
public Node getLoopNode(Node head){
	if(head==null||head.next==null||head.next.next==null){
		return null;
	}
	Node n1=head.next;//n1->slow
	Node n2=head.next.next;//n2->fast
	while(n1!=n2){
		if(n2.next==null||n2.next.next==null){
			return null;
		}
		n2=n2.next.next;
		n1=n1.next;
	}
	n2=head;//n2->walk again from head
	while(n1!=n2){
		n2=n2.next;
	}
	return n1;
}
发布了43 篇原创文章 · 获赞 21 · 访问量 4905

猜你喜欢

转载自blog.csdn.net/flying_1314/article/details/103921974