【一天一大 lee】环形链表II (难度:中等) - Day20201010

时间:2022-07-28
本文章向大家介绍【一天一大 lee】环形链表II (难度:中等) - Day20201010,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目:

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

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

说明: 不允许修改给定的链表。

进阶:

你是否可以不用额外空间解决此题?

示例:

  1. 示例 1:

示例1

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

示例2

输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。
  1. 示例 3:

示例3

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

抛砖引玉

思路

忽略进阶的逻辑,环形链表 (难度:简单)的逻辑依旧可以解决本题,只需要修改返回值

哈希表

  • 遍历链表一个节点就将遍历的节点作为哈希存放到(map、set、object)中
  • 后续又遇到则说明存在环,否则不存在
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var detectCycle = function(head) {
  let map = new Map()
  while (head !== null) {
    if (map.has(head)) return head
    map.set(head, true)
    head = head.next
  }
  return null
}

快慢指针

  • 声明两个指针,两个指针一快一慢(慢指针每次向后移动一个位置,而快指针向后移动两个位置)
  • 如果链表内有环,则两个指针一定会在环内相遇(快指针超过慢指针 1 圈,设快指针在圈内走了 n 圈相遇)
  • 如果最终两指针均遇到终点则说明无环

本题需要查询到入环的位置:

  • 相遇时快指针走了:a+n(b+c)+b
  • 快指走过的距离是慢指针的 2 倍:a+n(b+c)+b = 2(a + b)

=> a = n(b+c)-b = c+(n−1)(b+c)

可知,慢指针继续向后走和新其指针 start 从开始走将会在入环位置相遇

快慢指针

var hasCycle = function(head) {
  if (head === null) return null
  let slow = head,
    fast = head
  while (fast !== null) {
    slow = slow.next
    if (fast.next !== null) {
      fast = fast.next.next
    } else {
      return null
    }
    // 快慢指针相遇, 相遇点为slow
    // 快指针超过慢指针一个环的位置,那么慢支
    if (fast === slow) {
      let start = head
      while (start !== slow) {
        start = start.next
        slow = slow.next
      }
      return start
    }
  }
  return null
}