如何判断一个链表是否有环?以及提供入口节点解决方法

哈希表法

  1. 算法思路:遍历链表,使用一个哈希表来记录已经访问过的节点。对于链表中的每个节点,检查该节点是否已经在哈希表中。如果在哈希表中,说明链表存在环;如果遍历到链表的末尾(即节点为null)都没有在哈希表中发现重复节点,说明链表无环。

  2. 代码实现:

    ini 复制代码
    class ListNode {
            int val;
            ListNode next;
            ListNode(int x) {
                val = x;
                next = null;
            }
    }
    
     //哈希表法处理链表是否有环
        public boolean hasCycleHash(ListNode head) {
            HashSet<ListNode> visited = new HashSet<ListNode>();
            ListNode current = head;
            while (current != null) {
                // 如果当前节点已经在哈希表中,说明有环
                if (visited.contains(current)) {
                    return true;
                }
                // 将当前节点添加到哈希表中
                visited.add(current);
                current = current.next;
            }
            return false; // 遍历完链表没有发现环
        }
    
    public static void main(String[] args) {
            //测试无环场景
            ListNode nodeA = solution.new ListNode(1);
            ListNode nodeB = solution.new ListNode(2);
            ListNode nodeC = solution.new ListNode(3);
            ListNode nodeD = solution.new ListNode(4);
            ListNode nodeE = solution.new ListNode(5);
    
            nodeA.next = nodeB;
            nodeB.next = nodeC;
            nodeC.next = nodeD;
            nodeD.next = nodeE; // 无环
            boolean resultNoCycle = solution.hasCycleHash(nodeA);
            System.out.println("哈希法处理:链表是否有环: " + resultNoCycle); // 输出: 链表是否有环: false
    }

结果展示:

arduino 复制代码
哈希法处理:链表是否有环: false

快慢指针法

  1. 算法思路:设置两个指针,一个慢指针(slow)和一个快指针(fast)。慢指针每次移动一个节点,快指针每次移动两个节点。如果链表没有环,快指针会先到达链表末尾;如果链表有环,快指针会在环内追上慢指针,即快慢指针会相遇,此时说明链表存在环。

  2. 代码实现:

    ini 复制代码
        //创建节点信息
    	class ListNode {
    			        int val;
    			        ListNode next;
    			        ListNode(int x) {
    			            val = x;
    			            next = null;
    			        }
    	}
    //快慢法
    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; // 没有环
        }
    //测试
    public static void main(String[] args) {
            LinkedListCycle solution = new LinkedListCycle();
            ListNode node1 = solution.new ListNode(3);
            ListNode node2 = solution.new ListNode(2);
            ListNode node3 = solution.new ListNode(0);
            ListNode node4 = solution.new ListNode(-4);
            node1.next = node2;
            node2.next = node3;
            node3.next = node4;
            node4.next = node2; // 创建环
    
        // 测试链表是否有环
        //测试无环场景
    		node4.next = null ; // 无环
        boolean result = solution.hasCycle(node1);
        System.out.println("链表是否有环: " + result); // 输出: 链表是否有环: true
        //测试有环场景
        ListNode entryNode = solution.detectCycle(node1);
        if (entryNode != null) {
            System.out.println("环的入口节点值: " + entryNode.val); // 输出: 环的入口节点值: 2
        } else {
            System.out.println("链表无环");
        }
    }

结果展示:

makefile 复制代码
链表是否有环: true
环的入口节点值: 2

寻找环的入口

代码实现:

ini 复制代码
//找到环的入口节点
    public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) {
            return null; // 链表为空或只有一个节点,不可能有环
        }
        // 初始化快慢指针
        ListNode slow = head;
        ListNode fast = head;
        boolean hasCycle = false;
        // 使用快慢指针法检测环
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;

        if (slow == fast) {
            hasCycle = true; // 快慢指针相遇,说明有环
            break;
        }
    }
    if (!hasCycle) {
        return null; // 没有环
    }
    // 找到环的入口节点
    //p1从头开始,p2从相遇点开始
    ListNode p1, p2;
    p1 = head;
    p2 = slow;
    while (p1 != p2) {
        p1 = p1.next;
        p2 = p2.next;
    }
    return p1; // 返回环的入口节点
}
相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
晨米酱3 天前
AGENTS.md:Agent 的上下文策略层
面试·架构·agent
大勇前进3 天前
原生 PHP 还是 Laravel?小项目到底要不要上框架
后端
yuzhi_liu3 天前
我用 LangGraph4j 实现 Multi-Agent Supervisor
后端
alsmile3 天前
Node-RED 之外,国产规则引擎的新方案:基于标准语法,Go 先行实现
后端·开源·go
大白803 天前
PHP 内存溢出排查思路:看懂报错日志,精准定位问题
后端
二月龙3 天前
PHP 接口返回统一响应封装,让前后端对接更省心
后端