题目描述
一个链表中包含环,请找出该链表的环的入口结点;
解题思路
方法一
定义一个Set,遍历这个链表的所有节点,将遍历到的每个节点都加入Set;因为Set不能添加重复的节点;
所以,当添加节点失败的时候,这个节点就是链表中环的入口结点;
private class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
public ListNode EntryNodeOfLoop(ListNode pHead) {
if (pHead == null) {
return null;
}
ListNode pNode = pHead;
HashSet<ListNode> pSet = new HashSet<>();
while (pNode != null) {
if (!pSet.add(pNode)) {
return pNode; //Set添加节点失败,这个节点就是环的入口节点
}
pNode = pNode.next;
}
return null;
}
方法二
可以用快慢两个指针来解决问题;
两个指针fast和slow,fast以slow两倍速度前进;如果没有环,那么fast和slow不会相遇,此时返回null;如果有环,那fast和slow肯定会再次相遇,相遇的时候,fast刚好比slow多走了一圈环的长度;
用图来描述下,当fast与slow相遇时,fast走过的距离为a + b + c + b,而slow走过的距离为a + b;
因为fast是slow速度的两倍,则有a+b+c+b = 2*(a+b),推出a=c;
此时第三个指针p从X处,以和slow指针相同的速度前进,当它两相遇时,即为环的起点Y处;
public ListNode EntryNodeOfLoop(ListNode pHead) {
ListNode fast = pHead,slow = pHead;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
ListNode p = pHead;
while (p != slow) {
p = p.next;
slow = slow.next;
}
return p;
}
}
return null;
}