题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
思路
- 书中解法
- 查询是否有环,设定两个指针,第一个慢指针每次走一步,第二个快指针每次走两步。当快指针超过慢指针时,即链表中有环。
- 查询环中的节点数,可从 1 中获得在环中的某个节点,通过这个节点循环遍历,可以回到此节点,由此计算节点数 nodesInLoop。
- 从链表头开始,设定两个指针,第一个指针先走环中节点数 nodesInLoop 次数,然后第二个指针与第一个指针开始同时遍历,每次走一步,到两指针相会时,所指向的节点即为入口节点。
- 其他解法
双指针法
代码
- 书中解法
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode meetingNode = meetingNode(head);
// 链表中无环,直接返回 null
if (meetingNode == null) {
return null;
}
// 得到环中节点的数目
int nodesInLoop = 1;
ListNode pNode1 = meetingNode;
while (pNode1.next != meetingNode) {
pNode1 = pNode1.next;
nodesInLoop++;
}
// 先移动 pNode1,次数为环中节点的数目
pNode1 = head;
while (pNode1 != null && nodesInLoop > 0) {
pNode1 = pNode1.next;
nodesInLoop--;
}
// 再移动 pNode1 与 pNode2
ListNode pNode2 = head;
while (pNode1 != pNode2) {
pNode1 = pNode1.next;
pNode2 = pNode2.next;
}
return pNode2;
}
/**
* 查询链表中是否包含环
*
* @param pHead
* @return
*/
private ListNode meetingNode(ListNode pHead) {
// 空链表,直接返回 null
if (pHead == null) {
return null;
}
ListNode pSlow = pHead;
// 只有一个节点,直接返回 null
if (pSlow.next == null) {
return null;
}
ListNode pFast = pSlow.next;
// 遍历,直到慢指针与快指针相会并返回
while (pSlow != null && pFast != null) {
if (pFast == pSlow) {
return pFast;
}
pSlow = pSlow.next;
pFast = pFast.next;
if (pFast != null) {
pFast = pFast.next;
}
}
// 执行到这里,说明链表中无环
return null;
}
}
来源:oschina
链接:https://my.oschina.net/Oaki/blog/3197728