剑指Offer对答如流系列 - 链表中环的入口节点

面试题23:链表中环的入口节点

一、问题描述

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

  	public class ListNode {
            int val;
            ListNode next = null;
            
            ListNode(int val) {
                this.val = val;
            }
     }

二、问题分析

首先不能忽略链表中不包含环的情况,第一件事情必须先确定链表是否有环:我们可以使用两个引用,一个跑的快、一个跑的慢,同时出发,跑的快的追上跑的慢的自然说明有环。(术语是常说的快慢引用)

如果链表有环,第二件事是确定链表中的环节点的个数,在第一件事情中,快引用追上了慢引用,以追上的位置为起点(肯定在环中),走一圈,边走边计数。

现在问题转换为求 链表中倒数第k个结点。k的值为链表中环的长度。

三、问题解答

    public ListNode entryNodeOfLoop(ListNode head) {
        // 判断是否有环
        ListNode meetingNode=meetingNode(head);
        if(meetingNode==null) {
            return null;
        }

        //计算环中结点的数目
        int count=1;
        ListNode pNode1 = meetingNode.next;
        while(pNode1!=meetingNode){
            count++;
            pNode1=pNode1.next;
        }

        // 求链表中倒数第k个结点
        pNode1=head;
        for(int i=1;i<=count;i++) {
            pNode1=pNode1.next;
        }
        ListNode pNode2=head;
        while(pNode1!=pNode2) {
            pNode1=pNode1.next;
            pNode2=pNode2.next;
        }
        return pNode1;
    }

    private ListNode meetingNode(ListNode head) {
        if(head==null) {
            return null;
        }
        ListNode pSlow=head;
        ListNode pFast=head;
        while(pFast!=null) {
            pSlow=pSlow.next;
            pFast=pFast.next;
            if(pFast!=null) {
                pFast=pFast.next;
            }
            if(pSlow!=null && pSlow==pFast) {
                return pSlow;
            }
        }
        return null;
    }
发布了151 篇原创文章 · 获赞 3197 · 访问量 45万+

猜你喜欢

转载自blog.csdn.net/qq_42322103/article/details/104089419