原题

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

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

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

示例 1:

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

示例 2:

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

示例 3:

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

进阶:

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

原题url:https://leetcode-cn.com/problems/linked-list-cycle-ii/

解题

在这里贴一下题目所提供的节点结构,这样下面的代码就不重复贴了:

Definition for singly-linked list.
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}

利用集合

拿到题目的时候,一开始想到的就是利用集合,存储已经遍历过的节点,如果访问到 null,说明不是环;如果添加失败,说明已经添加过,那么一定是环,并且该节点就是环的入口;

顺便说一句,我认为集合所占空间应该不是很大,因为它只是存储对象的应用地址,当然了,集合本身也是一个新的对象,也会占用额外的空间。

让我们看看代码:

public class Solution {
public ListNode detectCycle(ListNode head) {
if (head == null) {
return null;
} ListNode current = head;
Set<ListNode> set = new HashSet<>();
while (current != null) {
// 添加成功,则继续访问下一个节点
if (set.add(current)) {
current = current.next;
continue;
} // 添加不成功,说明重复
return current;
} return null;
}
}

提交OK,执行用时:5 ms,内存消耗:37.7 MB,但是提交用时只战胜了30.99%的 java 提交记录,看来有必要优化一下。

找规律

以前我们判断链表是否有环,都是通过快慢指针最终是否相等。现在的话,因为环可能并不是首尾相连,所以只找一次可能不够了,需要继续寻找规律。

我们假设一开始 slow 指针走过的路程为 x,那么 fast 指针走过的路程就为 2x,即:

s = x;
f = 2x;

如果 fast 指针最终为 null,那么说明不是环。

如果 fast、slow 指针最终指向的节点相等,说明有环,并且, fast 指针比 flow 指针多走了 n 圈环的长度,那么我们假设环的长度为 b,那么可以得出:

f = x + nb;

可以得出:s = nb;

以上就是最重要的结论了,slow 指针其实也已经走了 n 圈环的长度了。那么,我们再假设从 head 节点到环入口节点的长度为 a,那么从快慢指针相遇节点再走 a 步,最终会走到哪儿呢?

最终也会走到环的入口节点,因为(nb + a)可以理解为(a + nb),相当于从 head 节点出发,达到环的入口节点处,又绕环走了 n 圈,所以也会走到环的入口。所以此时我们也找到环的入口节点了。

接下来让我们看看代码:

public class Solution {
public ListNode detectCycle(ListNode head) {
// 先利用快慢指针,如果最终能相遇,说明有环
ListNode slow = head;
ListNode fast = head;
while (true) {
// 快指针为null,说明没有环
if (fast == null || fast.next == null) {
return null;
} // 慢指针移动一步
slow = slow.next;
// 快指针移动两步
fast = fast.next.next;
// 快慢指针相等,说明相遇
if (fast == slow) {
break;
}
} // 再用两个指针,一个从头结点出发,一个从相遇点出发,两个指针每次移动1步,两个指针相遇的地方为环的入口
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
} return slow;
}
}

提交OK,执行用时:1 ms,内存消耗:37.8 MB,但是提交用时只战胜了55.14%的 java 提交记录,难道还有更加高效的方法?

我找了一个执行用时 0 ms 的代码,发现就是和我这个类似的,我将它的代码再次提交后,发现和我这个提交结果一样。看来那些比我们快的算法,可能是因为提交时间比较早,测试案例并不像现在那么多,所以不必担心了。

总结

以上就是这道题目我的解答过程了,不知道大家是否理解了。这道题目不仅要利用快慢指针,还要总结规律,最终也能解决,总的来说是一道很考验逻辑思维的题目。

有兴趣的话可以访问我的博客或者关注我的公众号、头条号,说不定会有意外的惊喜。

https://www.death00.top/

公众号:健程之道

力扣142——环形链表 II的更多相关文章

  1. 力扣 - 142. 环形链表 II

    目录 题目 思路1 代码实现 思路2 代码实现 题目 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链 ...

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

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

  3. Java实现 LeetCode 142 环形链表 II(二)

    142. 环形链表 II 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始 ...

  4. 【LeetCode】142. 环形链表 II

    142. 环形链表 II 知识点:链表:set:快慢指针 题目描述 给定一个链表,判断链表中是否有环. 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表 ...

  5. Leetcode 142.环形链表II

    环形链表II 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 说明:不允许修改给定的链表. 进阶:你是否可以不用额外空间解决此题? 链表头是X,环的第一个节点是Y,sl ...

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

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

  7. 力扣 - 92. 反转链表II

    目录 题目 思路1(迭代) 代码 复杂度分析 思路2(递归) 代码 复杂度分析 题目 92. 反转链表 II 思路1(迭代) 将反转链表分成3个部分:前一段未反转的部分.待反转链表部分.后一段未反转部 ...

  8. 代码随想录第四天| 24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点 、160.链表相交、142.环形链表II

    今天链表致死量 第一题 public static class ListNode { int val; ListNode next; ListNode() {} ListNode(int val) { ...

  9. LeetCode 142——环形链表 II

    1. 题目 2. 解答 2.1 方法 1 定义快慢两个指针,慢指针每次前进一步,快指针每次前进两步,若链表有环,则快慢指针一定会相遇. 当快慢指针相遇时,我们让慢指针指向头节点,快指针不变,然后每次快 ...

随机推荐

  1. jvm内存监控

    jstack -- 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程 ...

  2. NLP突破性成果 BERT 模型详细解读 bert参数微调

    https://zhuanlan.zhihu.com/p/46997268 NLP突破性成果 BERT 模型详细解读 章鱼小丸子 不懂算法的产品经理不是好的程序员 ​关注她 82 人赞了该文章 Goo ...

  3. 前端开发之BOM和DOM(转载)

    BOM BOM:是指浏览器对象模型,它使JavaScript可以和浏览器进行交互. 1,navigator对象:浏览器对象,通过这个对象可以判定用户所使用的浏览器,包含了浏览器相关信息. naviga ...

  4. SuperSocket SuperWebSocket并发数100限制的问题

    var wsSer = new WebSocketServer(); wsSer.NewMessageReceived += wsSer_NewMessageReceived;//有消息传入时事件 w ...

  5. 怎样打开.jar格式文件,怎样运行.jar格式文件

    当时第一次看到.jar文件不知道是什么鬼,以为是压缩包,直接就解压了,但是并没有什么用.所以在下为大家详细介绍如何打开.jar文件以及如何运行.jar文件.什么是.jar文件,简单的说就是java压缩 ...

  6. [转]Java多线程学习(总结很详细!!!)

    Java多线程学习(总结很详细!!!) 此文只能说是java多线程的一个入门,其实Java里头线程完全可以写一本书了,但是如果最基本的你都学掌握好,又怎么能更上一个台阶呢? 本文主要讲java中多线程 ...

  7. jq动画和停止动画

    使用jq 实现动画循环效果 <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...

  8. 2018-8-10-win10-uwp-读取保存WriteableBitmap-、BitmapImage

    title author date CreateTime categories win10 uwp 读取保存WriteableBitmap .BitmapImage lindexi 2018-08-1 ...

  9. 什么是redis

    什么是redis 1.Redis是远程的 有客户端和服务端,客户端和服务端可以布置在不同的机器上,两者经过redis自定义的协议远程传输和交互的,我们一般说的是服务端. 2.Redis是基于内存的 所 ...

  10. pytorch BiLSTM+CRF代码详解 重点

    一. BILSTM + CRF介绍 https://www.jianshu.com/p/97cb3b6db573 1.介绍 基于神经网络的方法,在命名实体识别任务中非常流行和普遍. 如果你不知道Bi- ...