算法系列-第十七题

31 阅读2分钟

题目名称:环形链表

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

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

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

示例 1:

输入:head = [3,2,0,-4], pos = 1

输出:true

解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0

输出:true

解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1

输出:false

解释:链表中没有环。


/**

* 解法一:双指针

* 思路:

* (1)设置快慢两个指针,初始都指向链表头。

* (2)遍历链表,快指针每次走两步,慢指针每次走一步。

* (3)如果快指针到了链表末尾,说明没有环,因为它每次走两步,所以要验证连续两步是否为 NULL。

* (4)如果链表有环,那快慢双指针会在环内循环,因为快指针每次走两步,因此快指针会在环内追到慢指针,二者相遇就代表有环。

* 时间复杂度: O(n),最坏情况下遍历链表n个节点

* 空间复杂度: O(1),仅使用了两个指针,没有额外辅助空间

*/

function hasCycle(head: ListNode | null): boolean {

if (head == null) return false;

  


// 快慢双指针

let fast: ListNode = head;

let slow: ListNode = head;

  


while (fast != null && fast.next != null) {

// 快指针移动两步

fast = fast.next.next; // 慢指针移动一步

slow = slow.next; // 相遇则有环

if (fast === slow) return true;

}

  


return false; // 到末尾则没有环

}


/**

* 解法二:哈希

* 思路:

* (1)使用哈希表来存储所有已经访问过的节点。

* (2)每次我们到达一个节点,如果该节点已经存在于哈希表中,则说明该链表是环形链表,否则就将该节点加入哈希表中。

* (3)重复这一过程,直到我们遍历完整个链表即可。

* 时间复杂度: O(n),最坏情况下遍历链表 n 个节点

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

*/

function hasCycle(head: ListNode | null): boolean {

if (head == null) return false;

  


const seenMap = new Map();

  


while (head != null) {

if (seenMap.has(head)) return true;

seenMap.set(head, 1);

head = head.next;

}

  


return false;

}