142.环形链表 II [中等]

86 阅读1分钟

题目

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

解法一

思路

快慢指针。这是个数学题。

图片.png

按照快慢指针的方式,从head开始走。慢的指针走1步,快的指针走2步。如果有环,肯定会相遇。

假设从head到环入口长度为a,入口处到相遇处长度为b,相遇处到入口处长度为b。

如果相遇的话,快的指针一定比慢的指针夺走了几圈。

快的指针走了a+b+n(b+c),慢的指针走了a+b(慢的在圈里可能也绕了下,但快的一定比慢的多走了几圈)。而快的每次都比慢的多走了2步。有:

a+b+n(b+c)=2(a+b),整理后有,a = c + (n-1)(b+c)

也就是说,如果一个指针从head开始走,另一个指针从相遇位置开始走,那么这两个指针一定在入口处相遇。

代码

    public ListNode detectCycle(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                ListNode p = head;
                while(p != slow) {
                    p = p.next;
                    slow = slow.next;
                }
                return p;
            }
        }
        return null;
    }

复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

解法二

思路

使用java的set结构,第一次遇到重复的就是入口点。

代码

    public ListNode detectCycle(ListNode head) {
        Set<ListNode> set = new HashSet<>();
        ListNode p = head;
        while (p != null) {
            if (set.contains(p)) {
                return p;
            }
            set.add(p);
            p = p.next;
        }

        return null;
    }

复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)