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

Posted jefferychenxiao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指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;
    }

以上是关于剑指Offer对答如流系列 - 链表中环的入口节点的主要内容,如果未能解决你的问题,请参考以下文章

剑指offer:链表中环的入口节点

剑指Offer - 面试题23:链表中环的入口节点

剑指 Offer II 022. 链表中环的入口节点

剑指offer 链表中环的入口结点

刷题记录-剑指offer23:链表中环的入口节点

剑指 Offer II 022. 链表中环的入口节点