剑指Offer(第2版)——面试题23:链表中环的入口节点

题目:

如果一个链表中包含环,如何找出环的入口节点?例如:在下图的链表中,环的入口节点是节点3。
在这里插入图片描述

解题思路
  • 第一步,如何确定链表中包含环:
    可以利用快慢指针法,确定链表是否带环。定义两个指针,同时从链表的头节点出发,然后同时往后走,快指针一次走两步,慢指针一次走一步。如果两指针相遇,则链表包含环;如果快指针走到链表末尾也没有相遇,那么链表就不包含环。
  • 第二步:如何得到环中节点的数目:
    在第一步使用快慢指针法时,如果两个指针相遇,则表明链表中存在环,并且两个指针相遇的节点一定在环中。随后,我们可以从这个节点出发,一边继续向前移动一边计数,当再次回到这个节点时,就可以得到环中节点数了。(这步可以省略,下面证明)
  • 第三步,如何找到环的入口节点:
    可以定义两个指针P1和P2指向链表的头节点。如果链表中的环有n个节点,指针P1先在链表上向前移动n步,然后两个指针以相同的速度向前移动。当指针P2指向的入口节点时,指针P1已经围绕着环走了一圈,又回到了入口节点,它们相遇的节点正好是环的入口节点。
    在这里插入图片描述

第二步可以省略的原因(即快慢指针相遇的节点,距离头节点的节点数,就是环中节点数目):
  因为快慢指针相遇时,快指针比慢指针多走了一个环的跳数,也就是环中节点的数目。而快指针一次走两步,慢指针一次走一步,快指针跳数一直是慢指针两倍,此时快指针与慢指针的跳数差等于慢指针的跳数,即当前节点距离头节点的跳数,所以此时相遇节点的位置,满足第三步的要求。

2.代码:

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution{
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead){
        if(!pHead) return NULL;
        //慢指针
        ListNode* p1 = pHead;
        //快指针
        ListNode* p2 = pHead;
        //判断快指针是否到达末尾
        while(p2 != NULL && p2->next != NULL){
            p1 = p1->next;
            p2 = p2->next->next;
            //如果两者相遇,说明链表包含环(第一步)
            if(p1 == p2){
                //慢指针返回头节点,此时快指针刚好比慢指针多走n步
                //n为环节点数目
                p1 = pHead;
                //第三步
                while(p1 != p2){
                    p1 = p1->next;
                    p2 = p2->next;
                }
                //入口节点
                return p1;
            }
        }
        return NULL;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值