一起刷 leetcode 之环形链表2

题目

这道题是 leetcode 的第 142 道题

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

对应的题目链接 环形链表2

 

题目解析

方法 1 :暴力 + 哈希表

暴力解法,用哈希表存储已经访问过的元素

时间复杂度:O(n)

空间复杂度:O(n)

public class Solution {
    // 方法1 暴力解法+哈希表
    public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) {
            return null;
        }
        Set set = new HashSet<>();
        while (head != null) {
            if (set.contains(head)) {
                return head;
            }
            set.add(head);
            head = head.next;
        }
        return null;
    }

 

方法 2:快慢指针

时间复杂度:O(n)
空间复杂度:O(1)
这种方法需要一段数学证明
下面的证明是在有环的前提下
假设从链表头到环形入口(不包括入口元素)有 a 个节点,环上有 b 个节点
用两个快慢指针从头节点开始,慢指针一次走 1 步,快指针一次走 2 步
如果有环时即快慢指针相遇
假设快指针走过的路程为 f
慢指针走过的路程为 s
因为快指针一次走2步,速度是慢指针的 2 倍,所以相遇时走过的路程也是慢指针的 2 倍 即 f = 2s
同时呢,快指针比慢指针多走了 n 倍的环的长度即 f = s + nb
那么我们根据
f = 2s
f = s + nb
可以得出 f = 2nb ,s = nb ,也就是说在相遇时,快慢指针都走了环的整数倍的长度
那想找到链表环的入口,怎么做呢?
从头节点走 a + nb 的长度就是对应的环的入口(这里可以自己画个带有环的链表感受一下)
刚好在快慢指针相遇时,慢指针已经走了 nb 的长度了,它再走 a 步就到了环的入口,刚好头结点到环的入口就是 a 步,所以在快慢指针相遇时,让头结点和慢指针一步一步的走,当他俩相遇时,慢指针对应的元素就是环的入口元素

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

 

你可能感兴趣的:(面试,leetcode,数据结构与算法)