• 面试算法22:链表中环的入口节点(1)


    题目

    如果一个链表中包含环,那么应该如何找出环的入口节点?从链表的头节点开始顺着next指针方向进入环的第1个节点为环的入口节点。

    例如,在如图4.3所示的链表中,环的入口节点是节点3。
    在这里插入图片描述

    分析

    第1步:确认是否包含环

    定义两个指针并同时从链表的头节点出发,一个指针一次走一步,另一个指针一次走两步。如果链表中不包含环,走得快的指针直到抵达链表的尾节点都不会和走得慢的指针相遇。如果链表中包含环,走得快的指针在环里绕了一圈之后将会追上走得慢的指针。因此,可以根据一快一慢两个指针是否能够相遇来判断链表中是否包含环。

    第2步:如何找到环的入口节点

    定义两个指针来解决。先定义两个指针P1和P2,指向链表的头节点。如果链表中的环有n个节点,第1个指针P1先在链表中向前移动n步,然后两个指针以相同的速度向前移动。当第2个指针P2指向环的入口节点时,指针P1已经围绕环走了一圈又回到了入口节点。
    在这里插入图片描述

    第3步:如何得到环中节点的数目

    前面在判断链表中是否有环时用到了一快一慢两个指针。如果两个指针相遇,则表明链表中存在环。两个指针之所以会相遇是因为快的指针绕环一圈追上慢的指针,因此它们相遇的节点一定是在环中。可以从这个相遇的节点出发一边继续向前移动一边计数,当再次回到这个节点时就可以得到环中节点的数目。

    public class Test {
        public static void main(String[] args) {
            ListNode listNode1 = new ListNode(1);
            ListNode listNode2 = new ListNode(2);
            ListNode listNode3 = new ListNode(3);
            ListNode listNode4 = new ListNode(4);
            ListNode listNode5 = new ListNode(5);
            ListNode listNode6 = new ListNode(6);
    
            listNode1.next = listNode2;
            listNode2.next = listNode3;
            listNode3.next = listNode4;
            listNode4.next = listNode5;
            listNode5.next = listNode6;
            listNode6.next = listNode3;
            ListNode result = detectCycle(listNode1);
            System.out.println(result.val);
        }
    
        public static ListNode detectCycle(ListNode head) {
            ListNode inLoop = getNodeInLoop(head);
            if (inLoop == null) {
                return null;
            }
    
            int loopCount = 1;
            for (ListNode n = inLoop; n.next != inLoop; n = n.next) {
                loopCount++;
            }
    
            ListNode fast = head;
            for (int i = 0; i < loopCount; i++) {
                fast = fast.next;
            }
    
            ListNode slow = head;
            while (slow != fast) {
                fast = fast.next;
                slow = slow.next;
            }
    
            return slow;
        }
    
        // 快慢指针找到相遇的节点
        private static ListNode getNodeInLoop(ListNode head) {
            if (head == null || head.next == null) {
                return null;
            }
    
            ListNode slow = head.next;
            ListNode fast = slow.next;
            while (slow != null && fast != null) {
                if (slow == fast)
                    return slow;
    
                slow = slow.next;
                fast = fast.next;
                if (fast != null)
                    fast = fast.next;
            }
    
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
  • 相关阅读:
    火热报名中|墨菲安全发起首届 OSCS 软件供应链安全技术论坛
    自动驾驶的关键在于安全、智能与舒适
    玩机进阶教程------修改gpt.bin分区表地址段 完全屏蔽系统更新 fast刷写分区表 操作步骤解析【二】
    机器学习:基于梯度下降算法的逻辑回归实现和原理解析
    【Java】匿名内部类开发使用场景
    【计算机视觉40例】案例27:人脸检测
    适合汽车应用的MAX49017ATA/VY、MAX40025AAWT、MAX40025CAWT、MAX40026ATA/VY(线性)微功耗比较器
    TCP发送数据、接受数据及TCP通信程序练习
    金蝶迷路“云”丛中
    Spring Boot2.7生成用于登录的图片验证码
  • 原文地址:https://blog.csdn.net/GoGleTech/article/details/133687466