题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
思路
两种解决思路(理解第二种思路建议画图,会更直观)
-
遍历每个元素放入hashMap中,结束的时候还没有重复值,说明没有环。遇到重复值,说明是环入口节点
-
快慢指针1。如果满指针走到尾,没有与快指针相遇则无环。如果快慢指针能相遇,说明必定有环,且相遇点在环内。如何确定入环结点
- 同样两个指针p1、p2指向头结点,如果环中有n(n=b+c)个结点,一个指针p2先走n步,之后两个指针同时走。相遇的结点就是环的入口。
- 为什么相遇的时候是环的入口?p2先走n步,再同时走。那么相当于先走的多走了b+c的距离。当p1走了a的距离,p2走了b+c+a距离。刚好到环的入口。
- 如何知道环中的节点数n?通过快慢指针可以确定是否有环,并且相遇点必定在环内。从这个节点出发,一边移动一边计数,当再次回到这个节点的时候,就可以得到环中的节点数。
- 同样两个指针p1、p2指向头结点,如果环中有n(n=b+c)个结点,一个指针p2先走n步,之后两个指针同时走。相遇的结点就是环的入口。
-
快慢指针2。第一种快慢指针实现稍微麻烦,可以从数学上来解题。当快慢指针p1,p2相遇的时候,将p2重新放置到头结点,然后同时移动。相遇点即为环的入口。证明如下:
import java.util.HashSet;
public class Offer23_EntryNodeOfLoop {
public ListNode entryNodeOfLoop_HashSet(ListNode pHead) {
if (pHead == null || pHead.next == null) return null;
HashSet<ListNode> hashSet = new HashSet<ListNode>();
while (pHead != null) {
if (hashSet.contains(pHead)) {
return pHead;
}
hashSet.add(pHead);
pHead = pHead.next;
}
return null;
}
public ListNode entryNodeOfLoop_FastSlow(ListNode pHead) {
if (pHead == null || pHead.next == null || pHead.next.next == null) return null;
ListNode slow = pHead.next;
ListNode fast = pHead.next.next;
while (slow != fast) {
if (fast.next == null || fast.next.next == null) return null;
fast = fast.next.next;
slow = slow.next;
}
fast = pHead;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
如果有兴趣可以看更多关于【两个链表相交的一系列问题】