geosmart / geosmart.io

勿助勿忘,深造自得
http://geosmart.github.io/
2 stars 0 forks source link

链表有环,求环节点的入口 #24

Open geosmart opened 4 years ago

geosmart commented 4 years ago

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 说明:不允许修改给定的链表。

HashSet求解

Floyd算法求解

Floyd判圈算法,也称龟兔赛跑算法,可用于判断链表、迭代函数、有限状态机是否有环。如果有,找出环的起点和大小。时间复杂度O(n),空间复杂度O(1)。

求解原理

image 假设相遇于 D 点,则快指针应该这时刚好套慢指针一圈( 2 倍速的必然结果,可以数学证明), 则此时快指针走的路程为 AB + BCDEB + BD (用 BCDEB 表示一圈)(字母序表示方向,AB 表示 A -> B)

代码


    /**
     * Floyd求链表中环的入口节点
     * 1.定义快慢指针求相遇点,快指针比慢指针快2倍;
     * 2.在相遇点,定义1个指针从头,1个指针从相遇点,一起开始逐步前进,下次相遇点即为环入口;
     * 时间复杂度:O(n)
     * 空间复杂度:O(1)
     *
     * @param head 链表头节点
     * @return 是否循环链表
     */
    public static ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) {
            return null;
        }
        //寻找相遇
        ListNode slow = head.next;
        ListNode fast = head.next.next;
        while (slow != fast) {
            if (fast == null || fast.next == null) {
                return null;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        //寻找环入口
        ListNode meetSlow = head;
        while (meetSlow != fast) {
            fast = fast.next;
            meetSlow = meetSlow.next;
        }
        return meetSlow;
    }