使用java解决环形链表问题

环形链表问题

1. 问题描述

在一个单向链表中,某个节点的 next 指针指向了之前的某个节点,从而形成了一个环。

通常有两个问题需要解决:

  1. 如何判断链表是否有环?
  2. 如果链表有环,如何找到环的起始节点?

2. 解题思路

1. 判断链表是否有环(Floyd 判圈算法 / 快慢指针法)

  • 使用 快指针 fast慢指针 slow
    • slow 每次走一步
    • fast 每次走两步
  • 如果 fast 追上 slow(即 fast == slow),说明链表中有环。
  • 如果 fastfast.next 为空,则链表无环。

2. 找到环的起始节点(Floyd 定理)

  • fastslow 相遇时,slow 已经走了 x 步,而 fast 走了 2x 步。
  • 假设 环入口节点 距离链表头 L,环的长度为 C,则 fastslow 相遇的位置 M 距离环入口 E 还有 d 步。
  • Floyd 定理推导出:
    • 从链表头(head)出发一个新指针 ptr,从相遇点 M 出发一个新指针 slow,二者每次走一步,最终会在环的起始节点 E 相遇

3. Java 代码实现

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

public class LinkedListCycle {
    // 方法1:判断链表是否有环
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) return false;

        ListNode slow = head;
        ListNode fast = head;

        while (fast != null && fast.next != null) {
            slow = slow.next;        // 慢指针走一步
            fast = fast.next.next;   // 快指针走两步

            if (slow == fast) {      // 相遇,说明有环
                return true;
            }
        }
        return false;
    }

    // 方法2:找到环的起始节点
    public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) return null;

        ListNode slow = head;
        ListNode fast = head;
        ListNode entry = head; // 用于寻找环的起始节点

        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;

            if (slow == fast) {  // 快慢指针相遇
                while (entry != slow) {  // 另一个指针从头开始,每次走一步
                    entry = entry.next;
                    slow = slow.next;
                }
                return entry;  // 返回环的入口
            }
        }
        return null;  // 无环
    }

    // 测试代码
    public static void main(String[] args) {
        // 构造环形链表:1 -> 2 -> 3 -> 4 -> 5 -> 3 (成环)
        ListNode head = new ListNode(1);
        ListNode node2 = new ListNode(2);
        ListNode node3 = new ListNode(3);
        ListNode node4 = new ListNode(4);
        ListNode node5 = new ListNode(5);
        
        head.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;
        node5.next = node3;  // 形成环,指向 node3

        LinkedListCycle solution = new LinkedListCycle();
        System.out.println("链表是否有环:" + solution.hasCycle(head));

        ListNode cycleStart = solution.detectCycle(head);
        System.out.println("环的起始节点:" + (cycleStart != null ? cycleStart.val : "无环"));
    }
}

4. 代码解析

1. hasCycle(ListNode head)
  • 功能:判断链表是否存在环。
  • 实现
    • 使用快慢指针,slow 走一步,fast 走两步。
    • 如果 slow == fast,说明链表有环。
    • 如果 fastfast.next 为空,则链表无环。
  • 时间复杂度:O(N),N 为链表节点数。
  • 空间复杂度:O(1),只使用了两个指针。
2. detectCycle(ListNode head)
  • 功能:找到环的起始节点。
  • 实现
    • 先使用 hasCycle() 方法判断是否有环。
    • 若有环,则从 head 处定义新指针 entry,与 slow 继续移动,每次走一步。
    • entry == slow,即为环的起点。
  • 时间复杂度:O(N),N 为链表节点数。
  • 空间复杂度:O(1),只使用了额外指针。

5. 测试结果

运行程序,输出:

链表是否有环:true
环的起始节点:3

说明:

  • hasCycle 正确检测到链表存在环。
  • detectCycle 正确返回了环的入口节点 3

6. 总结

  • 快慢指针法 是检测链表是否有环的高效方法,时间复杂度 O(N),空间复杂度 O(1)。
  • Floyd 定理 可帮助快速找到环的起始节点。
  • 适用于一般的单向链表,并可扩展到 N 个节点的情况。

这样,我们完整实现了 判断链表是否有环寻找环的起始节点 的 Java 代码! 🚀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

红烧白开水。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值