[路飞]leetcode-141.环形链表

647 阅读2分钟

「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战」。

题目描述

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中存在环,则返回 true 。 否则,返回 false

原题目

Map思路分析(哈希表思路)

此题第一种思路可以是Map方法,分析如下:

如果我们要判断链表是否有环,可以先创建一个map类型的结构

将每一个链表节点都放进去

遍历到最后

链表结束,那么这个链表就不是环形链表

链表出现重复项,此链表为环形链表

分析边界情况,如果此heade为null 或者只有一个节点,return false;

Map 代码

var hasCycle = function (head) {
    if (!head || !head.next) return false;

    const mapper = new Map();
    let currentNode = head.next;

    while (currentNode) {
        if (mapper.has(currentNode)) {
            return true;
        } else {
            mapper.set(currentNode, currentNode);
        }
        currentNode = currentNode.next;
    }

    return false;
};

复杂度分析

时间复杂度:O(N)O(N),其中 NN 是链表中的节点数。最坏情况下我们需要遍历每个节点一次。

空间复杂度:O(N)O(N),其中 NN 是链表中的节点数。主要为哈希表的开销,最坏情况下我们需要将每个节点插入到哈希表中一次。

快慢节点思路分析

快慢指针,顾名思义,首先需要两个指针,一快一慢

慢指针指向第一个变量,快指针指向下一个,每次向后移动,慢指针每次走一步,快指针每次走两步。

如果链表有环,则快慢指针一定会相遇(我理解这里是数学思维最大公约数的情况)

如果快慢指针相遇,则链表有环

如果快指针结束,则链表无环

边界值分析与Map同款。

图示分析

image.png

快慢指针代码实现

var hasCycle = function (head) {
    if (!head || !head.next) return false;
    let preNode = head;
    let nextNode = head.next;
    while (preNode !== nextNode) {
        if (!nextNode || !nextNode.next) return false;
        preNode = preNode.next;
        nextNode = nextNode.next.next;
    }

    return true;
};

复杂度分析

时间复杂度:O(N)O(N),其中 NN 是链表中的节点数。

当链表中不存在环时,快指针将先于慢指针到达链表尾部,链表中每个节点至多被访问两次。

当链表中存在环时,每一轮移动后,快慢指针的距离将减小一。而初始距离为环的长度,因此至多移动 NN 轮。

空间复杂度:O(1)O(1)。我们只使用了两个指针的额外空间。