LeetCode141、 环形链表

46 阅读2分钟

LeetCode 系列记录我学习算法的过程。

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第22天,点击查看活动详情

题目

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

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

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

示例:

image.png

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

image.png

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

image.png

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

提示:

  • 链表中节点的数目范围是 [0, 104]
  • -105 <= Node.val <= 105
  • pos 为 -1 或者链表中的一个 有效索引 。

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

思路

又是链表题,求当前链表是否存在环形链表,及同一个节点被两个节点指向

那就很简单了,只要遍历一遍,将遍历过的节点打上标记,只要再遍历到标记的节点就说明存在环形链表:

  • 首先定义指针变量进行遍历
  • 如果当前节点的下一节点有被标记,则返回 true
  • 反之则将当前节点打上标记,并将指针指向下一节点
  • 全部遍历结束则返回 false

代码实现

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
    // 定义变量遍历链表
    let t = head
    while(t?.next) {
        // 如果下一个节点有被标记,返回 true
        if(t.next?.flag) return true
        // 反之标记当前结点,并移动到下一节点
        t.flag = true
        t = t.next
    }
    // 遍历结束则返回 false
    return false
};

image.png

优化

题目给的进阶要求是不能对原链表进行操作,那这时就可以用双指针的思路来进行解答

通过双指针的快慢指针,慢指针每次走一步,快指针每次走两步,如果存在环形链表,那快慢指针一定会相遇:

var hasCycle = function(head) {
    // 定义快慢指针
    let slow = head, fast = head?.next
    while(fast && fast?.next) {
        // 快慢指针相遇返回 true
        if(fast === slow) return true
        // 慢指针走一步,快指针走两步
        slow = slow.next
        fast = fast.next?.next
    }
    // 遍历结束返回 false
    return false
};

image.png