描述

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

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

进阶

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

解法一:哈希表

思路

最直接的解法就是利用一个集合保存每次遍历的节点的引用。之后,从链表头开始遍历,每遍历一个节点,就判断该节点的引用是否在集合中,如果不在集合中,则将该节点的引用放入集合中;如果在集合中,则返回该节点的引用(环的入口)。当然,如果能遍历到链表尾部,此时链表无环,返回 null

Java 实现

/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/ import java.util.Set;
import java.util.HashSet; public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode curr = head;
Set<ListNode> nodesSeen = new HashSet<>();
while (curr != null) {
if (nodesSeen.contains(curr)) {
return curr;
}
nodesSeen.add(curr);
curr = curr.next;
}
return curr;
}
}

Python 实现

# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
curr = head
nodes_seen = set()
while curr:
if curr in nodes_seen:
return curr
nodes_seen.add(curr)
curr = curr.next
return curr

复杂度分析

  • 时间复杂度:\(O(n)\)
  • 空间复杂度:\(O(n)\)

解法二:双指针

思路

LeetCode 第 141 题一样,如果不想占用额外的空间的话,可以采用双指针的方式。

假设链表的起始节点为 A,环的入口节点为 B,两个指针(快慢指针)相交节点为 C,AB 两点之间的长度为 \(x\),BC 两点之间的长度为 \(y\),CB 两点之间的长度为 \(z\)。慢指针 slow 走过的长度为 \(x+y\),快指针 fast 为了“赶上”慢指针,应该走过的长度为 \(x + y + z + y\),同时,由于快指针的速度是慢指针的两倍,因此相同时间内,快指针走过的路程应该是慢指针(走过的路程)的两倍,即

\[x + y + z + y = 2 (x + y)
\]

化简得,

\[x = z
\]

因此,如果此时有另外一个慢指针 slow2 从起始节点 A 出发,则两个慢指针会在节点 B (环的入口)相遇。

Java 实现

/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/ public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next; if (slow == fast) {
ListNode slow2 = head;
while (slow != slow2) {
slow = slow.next;
slow2 = slow2.next;
}
return slow;
}
}
return null;
}
}
// Runtime: 1 ms
// Your runtime beats 100.00 % of python submissions.

Python 实现

# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
slow, fast = head, head
while fast and fast.next:
slow = slow.next
fast = fast.next.next if slow == fast:
slow2 = head
while slow != slow2:
slow = slow.next
slow2 = slow2.next
return slow
return None
# Runtime: 44 ms
# Your runtime beats 99.73 % of python submissions.

复杂度分析

  • 时间复杂度:\(O(n)\),其中 \(n\) 表示链表的长度。最坏的情况下(链表有环),需要迭代的次数为 \(x + y + z = n\) 次,因此时间复杂度为 \(O(n)\)
  • 空间复杂度:\(O(1)\),只需要存储 3 个引用

【LeetCode题解】142_环形链表2(Linked-List-Cycle-II)的更多相关文章

  1. Leetcode 141题 环形链表(Linked List Cycle) Java语言求解

    题目描述: 给定一个链表,判断链表中是否有环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 -1,则在该链表中没有环. Map ...

  2. [LeetCode题解]142. 环形链表 II | 快慢指针

    解题思路 本题是在141. 环形链表基础上的拓展,如果存在环,要找出环的入口. 如何判断是否存在环,我们知道通过快慢指针,如果相遇就表示有环.那么如何找到入口呢? 如下图所示的链表: 当 fast 与 ...

  3. LeetCode 141. 环形链表(Linked List Cycle)

    题目描述 给定一个链表,判断链表中是否有环. 进阶:你能否不使用额外空间解决此题? 解题思路 快慢指针,慢指针一次走一步,快指针一次走两步,若两者相遇则说明有环,快指针无路可走则说明无环. 代码 /* ...

  4. [LeetCode题解]141. 环形链表 | 快慢指针

    题目描述 给定一个链表,判断链表中是否有环. 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的 ...

  5. [LeetCode]题解(python):142-Linked List Cycle II

    题目来源: https://leetcode.com/problems/linked-list-cycle-ii/ 题意分析: 给定一个链表,如果链表有环,返回环的起始位置,否则返回NULL.要求常量 ...

  6. 【链表】Linked List Cycle II

    题目: Given a linked list, return the node where the cycle begins. If there is no cycle, return null. ...

  7. LeetCode 142. 环形链表 II(Linked List Cycle II)

    142. 环形链表 II 142. Linked List Cycle II 题目描述 给定一个链表,返回链表开始入环的第一个节点.如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整 ...

  8. [LeetCode] Linked List Cycle II 单链表中的环之二

    Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Foll ...

  9. [LeetCode] 142. Linked List Cycle II 单链表中的环之二

    Given a linked list, return the node where the cycle begins. If there is no cycle, return null. To r ...

  10. [算法][LeetCode]Linked List Cycle & Linked List Cycle II——单链表中的环

    题目要求 Linked List Cycle Given a linked list, determine if it has a cycle in it. Follow up: Can you so ...

随机推荐

  1. Android-上下文菜单Menu

    上一篇博客介绍了,Android-普通菜单Menu,而这篇博客介绍Android-上下文菜单Menu AndroidManifest.xml 中加入权限: <!-- 读取联系人数据的权限 --& ...

  2. 【算法34】蓄水池抽样算法 (Reservoir Sampling Algorithm)

    蓄水池抽样算法简介 蓄水池抽样算法随机算法的一种,用来从 N 个样本中随机选择 K 个样本,其中 N 非常大(以至于 N 个样本不能同时放入内存)或者 N 是一个未知数.其时间复杂度为 O(N),包含 ...

  3. Mina的ssl加密

    前面写的Mina的示例,都是可以通过telnet登录的,并且可以相互交互. 现在采用ssl加密的方式,对建立连接时,进行加密连接.这样,双方只有统一的加密,然后才可以连接. 密钥的生成之前有说过,里面 ...

  4. DBCC--CHECKDB--不可被替代的原因

    CHECKSUM不能发现的两类问题 1. 发生在内存中的页错误,如内存损坏+第三方程序修改等 2. MS SQL Server潜在BUG导致的逻辑错误,该类错误可以使用重建索引或重建约束来修复 CHE ...

  5. asp.net 网站监控方案

    前言:监控web网站方法有很多种,这篇文章说一下对windows服务器 asp.net网站的监控 采用的方案,Powershell + Influxdb + Grafana 1.PowerShell ...

  6. Easyui datagrid绑定数据,新增,修改,删除写法

    @{ ViewBag.Title = "xw_xsfl"; } <script type="text/javascript"> var editIn ...

  7. 第六章 ReentrantLock源码解析2--释放锁unlock()

    最常用的方式: int a = 12; //注意:通常情况下,这个会设置成一个类变量,比如说Segement中的段锁与copyOnWriteArrayList中的全局锁 final Reentrant ...

  8. AOP面向切面的基石——动态代理(一)

    其实动态代理在Java里不是什么新技术了,早在java 1.2之后便通过 java.lang.reflect.InvocationHandler 加入了动态代理机制. 下面例子中,LancerEvol ...

  9. 修改tomcat7编码问题(重定向等)

    修改tomcat默认编码格式: 修改tomcat下的conf/server.xml文件,找到如下代码: <Connector port="8080" protocol=&qu ...

  10. Ceres入门笔记

    介绍 Ceres可以解决下列形式的边界约束鲁棒非线性最小二乘问题 (1) $\min\limits_{x}\quad \frac{1}{2} \sum\limits_{i}\rho_{i}\left( ...