【剑指offer】23.链表中环的入口节点

题目描述

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

思路

两种解决思路(理解第二种思路建议画图,会更直观)

  • 遍历每个元素放入hashMap中,结束的时候还没有重复值,说明没有环。遇到重复值,说明是环入口节点

  • 快慢指针1。如果满指针走到尾,没有与快指针相遇则无环。如果快慢指针能相遇,说明必定有环,且相遇点在环内。如何确定入环结点

    • 同样两个指针p1、p2指向头结点,如果环中有n(n=b+c)个结点,一个指针p2先走n步,之后两个指针同时走。相遇的结点就是环的入口。
      • 为什么相遇的时候是环的入口?p2先走n步,再同时走。那么相当于先走的多走了b+c的距离。当p1走了a的距离,p2走了b+c+a距离。刚好到环的入口。
    • 如何知道环中的节点数n?通过快慢指针可以确定是否有环,并且相遇点必定在环内。从这个节点出发,一边移动一边计数,当再次回到这个节点的时候,就可以得到环中的节点数。
  • 快慢指针2。第一种快慢指针实现稍微麻烦,可以从数学上来解题。当快慢指针p1,p2相遇的时候,将p2重新放置到头结点,然后同时移动。相遇点即为环的入口。证明如下:
    在这里插入图片描述

import java.util.HashSet;

public class Offer23_EntryNodeOfLoop {

    public ListNode entryNodeOfLoop_HashSet(ListNode pHead) {
        if (pHead == null || pHead.next == null) return null;

        HashSet<ListNode> hashSet = new HashSet<ListNode>();
        while (pHead != null) {
            if (hashSet.contains(pHead)) {
                return pHead;
            }
            hashSet.add(pHead);
            pHead = pHead.next;
        }
        return null;
    }

    public ListNode entryNodeOfLoop_FastSlow(ListNode pHead) {
        if (pHead == null || pHead.next == null || pHead.next.next == null) return null;

        ListNode slow = pHead.next;
        ListNode fast = pHead.next.next;

        while (slow != fast) {
            if (fast.next == null || fast.next.next == null) return null;
            fast = fast.next.next;
            slow = slow.next;
        }

        fast = pHead;
        while (slow != fast) {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }

}

如果有兴趣可以看更多关于【两个链表相交的一系列问题

发布了89 篇原创文章 · 获赞 13 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Dawn510/article/details/105247531