每日算法随笔:环形链表

题解:环形链表

在这道题目中,我们需要判断一个链表是否存在环。环的定义是链表的某个节点可以通过连续跟踪 next 指针回到自身。如果存在这样的环,那么就返回 true,否则返回 false

方法一:使用哈希集合 (HashSet)

思路

  • 遍历链表,使用一个哈希集合 (HashSet) 存储每个访问过的节点。
  • 每遍历一个节点时,检查该节点是否已经存在于集合中。如果存在,说明链表中存在环;如果不存在,则将该节点加入集合中。
  • 如果遍历完整个链表都没有发现重复节点,说明链表中不存在环。

代码实现

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        Set<ListNode> set = new HashSet<ListNode>();
        ListNode curr = head;
        while (curr != null) {
            // 如果当前节点已经在集合中,说明有环
            if (!set.add(curr)) {
                return true;
            }
            curr = curr.next; // 继续遍历下一个节点
        }
        return false; // 如果遍历到链表末尾没有发现环
    }
}

复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的节点数。我们每个节点只遍历一次。
  • 空间复杂度:O(n),需要额外的哈希集合来存储每个访问的节点。

过程解析

  1. 初始化一个空的 HashSet
  2. 从头节点开始遍历链表,每遇到一个节点,检查它是否在 HashSet 中。如果在,说明有环,返回 true;否则,将该节点加入集合,继续遍历下一个节点。
  3. 如果遍历到了链表的末尾(即 curr == null),说明链表没有环,返回 false

方法二:快慢指针 (Floyd 判圈算法)

思路

  • 使用两个指针:一个快指针 (fast),一个慢指针 (slow)。
  • 快指针每次走两步,慢指针每次走一步。
  • 如果链表中没有环,快指针会在遍历完链表时到达 null
  • 如果链表中有环,快指针会最终追上慢指针,两者会相遇。

代码实现

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) return false;

        ListNode slow = head; // 慢指针
        ListNode fast = head.next; // 快指针

        // 快慢指针相遇说明有环
        while (fast != slow) {
            if (fast == null || fast.next == null) return false; // 快指针提前到达终点,说明没有环
            fast = fast.next.next; // 快指针走两步
            slow = slow.next; // 慢指针走一步
        }

        return true; // 两个指针相遇,说明有环
    }
}

复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的节点数。最坏情况下,快指针和慢指针遍历链表中的每个节点。
  • 空间复杂度:O(1),我们只用了常数级别的额外空间。

过程解析

  1. 快指针 fast 每次走两步,慢指针 slow 每次走一步。
  2. 如果链表中有环,快指针最终会追上慢指针,这时返回 true
  3. 如果快指针在遍历过程中到达了 null,则链表没有环,返回 false

方法比较:

  1. 哈希集合法使用了额外的存储空间,但思路简单易懂,适合初学者。
  2. 快慢指针法虽然稍微复杂一点,但它不需要额外的空间,能够以 O(1) 的空间复杂度解决问题,在面试中常被要求使用这种方法。

这道题目考察了链表的基本操作以及快慢指针的应用,通过分析链表的结构,可以更好地掌握链表与指针的使用。

posted @ 2024-09-10 15:08  鱼摆摆不摆  阅读(19)  评论(0编辑  收藏  举报