Leetcode #141. Linked List Cycle刷题手记

74 阅读2分钟

141. Linked List Cycle

141. Linked List CycleLeetcode面试榜单Top150链表类第一题,输入给定链表头head, 判断出链表是否有环。链表和数组的两个不同特点是链表不能通过索引直接读到节点,以及链表是通过子节点指针遍历节点。在设计算法时,和数组类数据类似,可以直观考虑用辅助内存空间(额外数组,栈,队列,集合,字典等数据结构),也可以考虑只用一个或者多个节点指针遍历计算在原列表中记录修改来优化空间复杂度,降低空间使用。

本题一个思路可以考虑用个额外字典来存储遍历过程中节点作为字典的key, 遍历一个节点时观察该节点在字典中计数是否已经大于0(则是在此节点形成环),若遍历到尾节点(next为null),则不存在环。时间复杂度和空间复杂度都是O(n). 用快慢两个指针遍历的方法可以优化空间复杂度为O(1),快指针一次循环前进两个节点,慢指针一个节点,直到快指针遇上慢指针(有环的case),或者到尾节点(next为null).

解法1:利用字典数据结构作为辅助内存

public class Solution {
    public boolean hasCycle(ListNode head) {
        Set<ListNode> nodesSeen = new HashSet<>();
        while (head != null) {
            if (nodesSeen.contains(head)) {
                return true;
            }
            nodesSeen.add(head);
            head = head.next;
        }
        return false;
    }
}

解法2:Floyd环路查找法(利用快慢指针优化掉辅助内存的使用)

public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null) {
            return false;
        }

        ListNode slow = head;
        ListNode fast = head.next;
        while (slow != fast) {
            if (fast == null || fast.next == null) {
                return false;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        return true;
    }
}

在数组数据结构的算法中的一些基本策略也是用于链表数据类的算法设计,如遍历,使用辅助数据结构临时存储中间计算结果。