题目
一个链表中包含环,请找出该链表的环的入口结点。
思路1
利用HashSet元素不能重复,将链表从头开始依次添加到HashSet中,并判断每次添加是否成功,显然第二次到达环的入口时添加会失败,直接返回当前节点即可。
/**
* 解法1:使用HashSet元素不能重复做
*/
public ListNode entryNodeOfLinkedNode2(ListNode pHead) {
HashSet<ListNode> hashSet = new HashSet<>();
while (pHead != null) {
//当第二次到达环入口,由于节点已经在set中,添加会失败
if (!hashSet.add(pHead)) {
return pHead;
}
pHead = pHead.next;
}
return null;
}
思路2
1)快慢指针方法,判定是否存在环,并记录两指针相遇位置(Z);
2)将两指针分别放在链表头(X)和相遇位置(Z),并改为相同速度推进,则两指针在环开始位置相遇(Y)。
第二步的证明如下:
如下图所示,X,Y,Z分别为链表起始位置,环开始位置和两指针相遇位置,串长a + (b+c)
,其中b+c
为环的长度,当走了a + b
步的慢指针与快指针相遇时,快指针已经走过了k圈。则根据快指针速度为慢指针速度的两倍,可以得出:
2 * (a+b) = a + b + k * (b+c)
a = k * (b+c) - b = (k-1)*(b+c) +c
此时两指针分别放在起始位置和相遇位置,并以相同速度前进,从X走完距离a时,Z恰好绕环k-1
圈并加上c的距离,
两指针同时到达Y,即相遇在环的入口。
package com.zhumq.leetcode;
import java.util.HashSet;
public class EntryNodeOfLinkedList {
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
/**
* 解法2:快慢指针
* @param pHead
* @return
*/
public ListNode entryNodeOfLinkedList(ListNode pHead) {
//为空,或者只有一个节点,或者只有两个节点且第二个节点next为空
if (pHead == null || pHead.next == null || pHead.next.next == null)
return null;
//快慢指针
ListNode fast = pHead.next.next;
ListNode slow = pHead.next;
//先判断有没有环
while (fast != slow) {
if (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
} else {
//没有环
return null;
}
}
//有环把fast指向头节点
fast = pHead;
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
return fast;
}