啃算法:04 判断链表是否有环

80 阅读1分钟

有一个单向链表,链表当中有可能出现“环”,如何用程序判断出这个链表是有环链表? 不允许修改链表结构。时间复杂度O(n),空间复杂度O(1)。

什么叫有环,比如说,链表 一开始是 a-z,突然变成了 z指向了a到z的任何一个数据,导致链表循环无法退出。

通过set集合判断包含

思路是我们在遍历链表的时候,将当前节点的next和set 进行判断是否包含,一个不包含我们就将next 添加到set里面去,如果包含就返回。 为了解决头结点就是环节点问题,我们将头节点主动添加到set中,然后循环next节点。

    private static boolean haveLoop(ListNode head) {
        ListNode node=head;
        Set<ListNode> nodes=new HashSet<>();
        nodes.add(head);
        while (node.next!=null){
            if (!nodes.contains(node.next)){
                nodes.add(node.next);
                node = node.next;
            }else {
                return true;
            }
        }
        return false;
    }

这种解法的空间复杂度和时间复杂度都是O(n)。

双指针追赶判断是否有环

思路是如果有环,跑得快点在第N轮循环中会遇到跑得慢的。如果没有环,那么跑得慢的和跑得的永远不会相遇。

    private static boolean haveLoop(ListNode head) {
        ListNode slow=head;
        ListNode fast=head;
        while (fast!=null&&fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
            if (fast==slow){
                return true;
            }
        }
        return false;
    }

那么使用快指针作为循环的条件和慢指针作为循环到条件有什么区别呢?

我们回顾一下前提条件,如果说没有环,快指针执行会更快,如果有如果有环,快慢指针作为循环的条件都没有区别。

所以这种写法的时间复杂度是O(n),空间复杂度是O(1)。