剑指offer-面试题23:链表中环的入口节点 快慢指针+双指针

题目描述

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。如图所示,节点3是链表中环的入口节点
在这里插入图片描述

本题的解决分为两步:(1)确定链表中是否有环(2)如果有环,确定环的入口节点。我们使用双指针法解决此问题

第一步:确定链表中是否有环(快慢指针)

我们使用快慢指针法,它是双指针的一种形式。定义两个指针p1、p2,起始点都在链表的头结点;p1是慢指针每次向前走一步,p2是快指针每次向前走两步;若不存在环,p2会率先到达尾结点的next,即null,此时便可以返回null;若存在环,p2会率先进入环并在环中做循环运动,p1后进入环中,而后p2总会在环中的某一点追上p1;确定有环;

在上图的链表中,p2会在节点5处被p1追上

第二步:确定环的入口节点(双指针法)

这里我们使用上一步的两个指针

要确定环的入口节点,首先要知道环的长度。如上图中的链表,我们从p1、p2相遇的节点5开始,p1再向前走4步会再次回到节点5,由此确定了环的长度为4

已经确定了环的长度n。让p1、p2都回到链表头结点;然后p1不动,p2先向前走n步;接下来p1和p2均一次走一步,直到p1和p2相遇,相遇点就是环的入口点。那么如何证明这一点呢?

证明:
假设链表非环部分长为l,环部分长为n

若l==n,p2先走n=l步到达环的入口;p1走到l步到达环的入口处时p2恰好走n步,绕环一圈回到环的入口与p1相遇

若l<n,p2先走n步,距离环的入口还有l-n;p1走l步到环的入口时,p2也走了l步,因为n+l-n=l,所以此时p2也绕环一圈回到环的入口和p1相遇

若l>n,p2先走n步,已经进入了环n-l步,距离下一次到达环入口还有l步;p1走l步到环的入口时,p2也走l步到达环的入口与p1相遇

因此,当p2先走环的长度步,p1、p2再开始以相同速度前进,p2总会在绕环一周后与p1在环的入口相遇

解题代码:

class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
public class Solution {
    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        if(pHead==null)
        {
            return null;
        }
        ListNode p1=pHead,p2=pHead;
        while(p2!=null) //确定是否有环,p1慢指针,p2快指针
        {
            p1=p1.next;
            if(p2.next!=null && p2.next.next!=null)
            {
                p2=p2.next.next;
                if(p1==p2) //再次相遇,链表中有环
                {
                    int lenCircle=1;
                    p2=p2.next;
                    while(p2!=p1) //计算环的长度
                    {
                        p2=p2.next;
                        lenCircle++;
                    }
                    p1=pHead;
                    p2=pHead;
                    for(int i=0;i<lenCircle;i++) //p2向前走环长度的步数
                    {
                        p2=p2.next;
                    }
                    while(p1!=p2)
                    {
                        p1=p1.next;
                        p2=p2.next;
                    }
                    break; //p1、p2再次相遇点就是环的入口
                }
            }
            else
            {
                return null;
            }
        }
        return p2;
    }
}

时间复杂度:O(n)
空间复杂度:因为只使用了两个指针,因此是O(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值