题目描述
- 一个链表中包含环,请找出该链表的环的入口结点。
- 地址:牛客地址
题目分析
- 用额外空间:
遍历链表,用HashSet存储已遍历节点,假如遍历到curNode时,set中已经存在,说明这是入环节点,返回。若不存在,装入set中 不用额外空间
- 首先判断有没有环
用快慢指针,fast 与 slow,起初,都指向头结点,然后快指针走两步,慢指针走一步,直到快慢指针相遇,若是跳出循环时,fast == slow 说明有环,否则,则是因为单链表到末尾跳出的,说明无环 - 然后找入环的第一个节点
将快指针指向头部,然后快慢指针相同速度,都是快一慢一,最终快慢指针相遇的地方便是入环节点
具体证明见牛客讨论区或剑指offer
- 首先判断有没有环
经验教训
- 快慢指针如何确定是否有环
- 若有环,如何确定入环节点
代码实现
- 用额外空间
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead == null || pHead.next == null || pHead.next.next == null) {
return null;
}
HashSet<ListNode> set = new HashSet<>();
ListNode curNode = pHead;
while (curNode != null) {
if (set.contains(curNode)) {
return curNode;
}
set.add(curNode);
curNode = curNode.next;
}
return null;
}
- 不用额外空间
public ListNode EntryNodeOfLoop(ListNode pHead){
//链表为空或者链表只有一个节点或者链表只有两个节点,肯定无环
if(pHead == null || pHead.next == null || pHead.next.next == null) {
return null;
}
//确定是否有环
ListNode slow = pHead.next;
ListNode fast = pHead.next.next;
//快2慢1走
while (slow != fast && fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
//无环
if (slow != fast) {
return null;
}
//有环,确定入环节点
//慢不变,快到头结点,快1慢1
fast = pHead;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}