拼潦 发表于 2025-12-25 09:40:00

剑指offer-55、链表中环的⼊⼝节点

题⽬描述

给⼀个链表,若其中包含环,请找出该链表的环的⼊⼝结点,否则,输出null 。
例如,输⼊{1,2},{3,4,5} 时,对应的环形链表如下图所示:

可以看到环的⼊⼝结点的结点值为3,所以返回结点值为3的结点。
给定的链表节点的结构:
public class ListNode {
    int val;
    ListNode next = null;
    ListNode(int val) {
            this.val = val;
    }
}思路及解答

借用HashSet

直接使⽤ HashSet ,历链表的时候,如果 HashSet 中不包含,则添加到 HashSet 中,如果链表中包含,说明已经回到环的第⼀个节点。Java 代码实现如下:
public ListNode EntryNodeOfLoop(ListNode pHead) {
    HashSet set = new HashSet();
    while(pHead!=null){
      if(set.contains(pHead)){
              return pHead;
      }else{
            set.add(pHead);
            pHead = pHead.next;
      }
    }
    return null;
}

[*]时间复杂度:O(n) - 每个节点最多访问一次
[*]空间复杂度:O(n) - 最坏情况下需要存储所有节点
双指针

上⾯的做法时间复杂度为O(n) ,由于借助了⼀个hashSet ,空间复杂度也为O(n) 。那假设我们不需要使⽤额外的空间呢?怎么做呢?
使⽤快慢双指针,⼀个⼀次⾛⼀步,⼀个⼀次⾛两步,当两个重合在⼀起的时候,这时候,并不是环的⼊⼝节点。只能说明两个指针,⼀个⽐另外⼀个多⾛了若⼲圈,可能是⼀圈,可能是2 , 3 圈。

⽐如上⾯的,如果开始节点是A ,环的⼊⼝是B ,相遇的节点是C ,那么

[*]慢指针⾛的距离是: S=AB+BC
[*]快指针⾛的距离是: 假设多⾛了n圈,2S = AB+(BC+CB)*n+BC ,
即 2(AB+BC) = AB+(BC+CB)*n+BC,也就是AB+BC = (BC+CB)*n
假设n =1 ,那么AB = CB ,也就是当前位置到环的⼊⼝的⻓度,等于链表头到环的⼊⼝的位置。
因此相遇之后,我们将⼀个快指针移动到链表头,两个指针每次⼀步,直到相遇,这个时候,相遇的节点就是环的⼊⼝节点。
public ListNode EntryNodeOfLoop(ListNode pHead) {
    ListNode quick = pHead;
    ListNode slow = pHead;
    while (quick != null && slow.next != null) {
      quick = quick.next;
      slow = slow.next.next;
      if (quick == slow) {
            quick = pHead;
            while (quick != slow) {
                quick = quick.next;
                slow = slow.next;
            }
            return quick;
      }
    }
    return null;
}

[*]时间复杂度: O(n)
[*]空间复杂度: O(1)
标记法(破坏性解法)

通过修改节点结构来标记已访问的节点,适合可以修改链表的情况
public class Solution {

    public ListNode detectCycle(ListNode head) {
      if (head == null) return null;
      
      // 使用特殊值标记已访问节点
      final int MARKER = Integer.MIN_VALUE;
      ListNode current = head;
      
      while (current != null) {
            // 如果遇到标记值,说明是环的入口
            if (current.val == MARKER) {
                // 恢复原始值(可选)
                return current;
            }
            // 标记当前节点
            current.val = MARKER;
            current = current.next;
      }
      
      return null;
    }
   
    /**
   * 替代方案:使用额外字段进行标记(如果节点结构可扩展)
   */
    static class MarkableListNode {
      int val;
      MarkableListNode next;
      boolean visited;
      
      MarkableListNode(int val) {
            this.val = val;
            this.visited = false;
      }
    }
}

[*]时间复杂度:O(n) - 线性遍历
[*]空间复杂度:O(1) - 但破坏了链表结构

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

卿搞笔 发表于 2025-12-27 03:34:27

很好很强大我过来先占个楼 待编辑

垢峒 发表于 2026-1-7 08:28:56

前排留名,哈哈哈

骛扼铮 发表于 2026-1-18 03:24:45

感谢分享,学习下。

役魅肋 发表于 2026-1-19 01:23:54

鼓励转贴优秀软件安全工具和文档!

杭环 发表于 2026-1-19 04:49:11

感谢发布原创作品,程序园因你更精彩

颜才 发表于 2026-1-20 19:16:21

鼓励转贴优秀软件安全工具和文档!

叟减 发表于 2026-1-24 09:46:46

感谢分享,学习下。

崔竹 发表于 2026-1-27 04:47:42

感谢,下载保存了

梁丘眉 发表于 2026-1-28 01:16:29

收藏一下   不知道什么时候能用到

古修蟑 发表于 2026-1-29 03:30:07

谢谢分享,试用一下

仲水悦 发表于 2026-2-8 21:31:52

感谢分享,学习下。

印萍 发表于 2026-2-9 10:33:19

感谢,下载保存了

沦嘻亟 发表于 2026-2-13 10:20:24

谢谢分享,辛苦了

福清婉 发表于 2026-2-24 12:00:10

感谢分享

材部 发表于 2026-2-24 16:50:44

谢谢楼主提供!

轩辕娅童 发表于 2026-2-25 09:19:20

感谢分享

喳谍 发表于 2026-3-5 03:44:01

感谢发布原创作品,程序园因你更精彩

蝌棚煌 发表于 2026-3-9 10:22:02

热心回复!

晾棋砷 发表于 2026-3-12 04:22:15

热心回复!
页: [1]
查看完整版本: 剑指offer-55、链表中环的⼊⼝节点