leetcode 141. 环形链表 JavaScript版

1,245 阅读2分钟

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

题目来源:LeetCode-141. 环形链表

题目

给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

示例 1:

image.png

输入: head = [3,2,0,-4], pos = 1
输出: true
解释: 链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入: head = [1,2], pos = 0
输出:true
解释: 链表中有一个环,其尾部连接到第一个节点。

image.png

示例 3:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

image.png

题解

提出问题

  • 如何证明链表中有环?

分析

  • 当链表中存在一个节点,可以通过连续跟踪 next 指针再次到达,则证明链表中存在环。

解法

  • 通过遍历链表方式把每一个节点都通过set方式到Map对象中;
  • set之前先通过has方式判断Map对象中是否存在该结点,如果存在,则为有环;
  • 当遍历完成也就是 next 指针指向null的话,则为无环。

代码实现

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
  let pointer = head;
  let map = new Map();
  while (pointer !== null) {
    if (map.has(pointer)) {
      return true; 
    } else {
      map.set(pointer);
      pointer = pointer.next; 
    }
  }
  return false; 
};

空间复杂度

上述代码中的Map对象由于Map对象所占用的空间是受到链表影响的空间复杂度为O(N)

空间复杂度

上述代码中通过while遍历链表是受到链表长度影响的时间复杂度为O(N)

进阶

你能用 O(1) (即,常量)内存解决此问题吗?

提出问题

  • 如何通过不存储链表节点来证明链表中有环?

分析

  • 可以通过快慢指针(快指针每次走两步,慢指针每次走一步);
  • 当快指针的下一位仍有数值时,通过while继续移动快慢指针;
  • 如果快指针和慢指针相遇(重合),说明该链表是有环链表,返回True;
  • 如果快指针走到链表尾仍没有遇到慢指针,说明是无环链表,返回False。

代码实现

/**
 * @param {ListNode} head
 * @return {boolean}
 */
 var hasCycle = function(head) {
    let fast = head;
    let slow = head;
    while(fast&&slow&&fast.next){
        fast = fast.next.next;
        slow = slow.next;
        if(slow == fast)return true

    }
    return false;
};

趣味实验

分析

  • 遍历有环的链表会一直执行下去(死循环)
  • 把一个死循环的链表对象转换JSON字符串会报错

无环链表

image.png

有环链表

image.png

通过上述实验可以证明有环的链表转换成JSON对象会报错

  • 可以通过try catch来捕获错来判断是否有环

代码实现

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
  try {
    JSON.stringify(head);
    return false;
  } catch (err) {
    return true;
  }
};