【LeetCode】141.环形链表、142. 环形链表 II(算法 + 图解)

Hi~!这里是奋斗的明志,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~
🌱🌱个人主页:奋斗的明志
🌱🌱所属专栏:数据结构

在这里插入图片描述

📚本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为展示我的学习过程及理解。文笔、排版拙劣,望见谅。

在这里插入图片描述

链表面试题

  • 一、环形链表
    • 1. 题目
    • 2. 解析
    • 3. 完整代码
  • 二、环形链表 II
    • 1. 题目
    • 2. 解析
    • 3. 完整代码
  • 三、总结

一、环形链表

141.环形链表


1. 题目


在这里插入图片描述
在这里插入图片描述


2. 解析


【思路】

快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表起始位置开始运行,如果链表 带环则一定会在环中相遇,否则快指针率先走到链表的末尾。比如:陪女朋友到操作跑步减肥。

【扩展问题】

  • 为什么快指针每次走两步,慢指针走一步可以?

假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚进环时,可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。此时,两个指针每移动一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情况,因此:在慢指针走到一圈之前,快指针肯定是可以追上慢指 针的,即相遇。

  • 快指针一次走3步,走4步, …n步行吗?

在这里插入图片描述

在这里插入图片描述


快慢指针初始化:

  • ListNode fast = head;:快指针从链表头部开始。
  • ListNode slow = head;:慢指针也从链表头部开始。

遍历过程:

  • while (fast != null && fast.next != null):使用快指针和慢指针遍历链表,条件是快指针不为 null 且快指针的下一个节点也不为 null。
  • fast = fast.next.next;:快指针每次向前移动两步。
  • slow = slow.next;:慢指针每次向前移动一步。

检测环:

  • if (fast == slow):在每次迭代中,检查快慢指针是否相遇。如果相遇,说明链表中存在环,返回 true。

结束条件:

  • 如果遍历完链表(即 fast 或者 fast.next 为 null ),仍未找到相遇点,则链表中不存在环,返回 false。

总结:

  • 该算法利用快慢指针的技巧来判断单链表中是否存在环,时间复杂度为 O(n)空间复杂度为 O(1),非常高效。

3. 完整代码


/*** Definition for singly-linked list.* class ListNode {* int val;* ListNode next;* ListNode(int x) {* val = x;* next = null;* }* }*/
public class Solution {public boolean hasCycle(ListNode head) {// 定义两个指针ListNode fast = head;ListNode slow = head;// 使用快慢指针进行遍历while (fast != null && fast.next != null) {fast = fast.next.next; // 快指针每次走两步slow = slow.next; // 慢指针每次走一步if (fast == slow) { // 如果快慢指针相遇,说明有环return true;}}return false; // 遍历结束,没有环}
}

二、环形链表 II

142. 环形链表 II


1. 题目


在这里插入图片描述
在这里插入图片描述


2. 解析

重画链表如下所示,线上有若干个节点。记蓝色慢指针为 slow,红色快指针为 fast。初始时 slow 和 fast 均在头节点处。
在这里插入图片描述
使 slow 和 fast 同时前进,fast 的速度是 slow 的两倍。当 slow 抵达环的入口处时,fast 一定在环上,如下所示。
在这里插入图片描述
其中:

head 和 A 的距离为 z
弧 AB (沿箭头方向) 的长度为 x
同理,弧 BA 的长度为 y

可得:

slow 走过的步数为 z
设 fast 已经走过了 k 个环,k≥0,对应的步数为 z+k(x+y)+x
以上两个步数中,后者为前者的两倍,即 2z=z+k(x+y)+x 化简可得 z=x+k(x+y),替换如下所示。
在这里插入图片描述
此时因为 fast 比 slow 快 1 个单位的速度,且y 为整数,所以再经过 y 个单位的时间即可追上 slow。

即 slow 再走 y 步,fast 再走 2y 步。设相遇在 C 点,位置如下所示,可得弧 AC 长度为 y。

在这里插入图片描述

因为此前x+y 为环长,所以弧 CA 的长度为 x。 此时我们另用一橙色指针 ptr (pointer) 指向 head,如下所示。并使 ptr 和 slow 保持 1 个单位的速度前进,在经过 z=x+k(x+y) 步后,可在 A 处相遇。
在这里插入图片描述
再考虑链表无环的情况,fast 在追到 slow 之前就会指向空节点,退出循环即可。


在这里插入图片描述


由上一题可以求出相遇点,这里的相遇点是假设的
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
走不确定圈数的时候:


在这里插入图片描述
在这里插入图片描述
初始化指针:

  • ListNode fast = head;:快指针从链表头部开始。
  • ListNode slow = head;:慢指针也从链表头部开始。

检测环:

  • 使用两个指针 fastslow 同时遍历链表,其中 fast 每次移动两步,而 slow 每次移动一步``。
  • 如果链表中存在环,快指针 fast 最终会追上慢指针 slow

找出环的起始点:

  • 一旦快慢指针相遇,就说明链表中有环。
  • 将 slow 指针重新指向链表头部。
  • 接着,快指针 fast 和慢指针 slow 同时每次移动一步,直到它们再次相遇。这次相遇点即为环的起始点。

返回结果:

  • 如果找到了环的起始点,就返回这个节点;否则返回 null,表示链表中无环。

3. 完整代码


/*** 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 fast = head;ListNode slow = head;while(fast != null && fast.next != null){fast = fast.next.next;slow = slow.next;if(fast == slow){slow = head;while(fast != slow){fast = fast.next;slow = slow.next;}return fast;}}return null;}
}

三、总结

  • 链表(Linked List)是最简单的线性的、动态数据结构。理解它是理解树结构、图结构的基础。

  • 区别于数组,链表中的元素不是存储在内存中连续的一片区域,链表中的数据存储在每一个称之为「结点」复合区域里,在每一个结点除了存储数据以外,还保存了到下一个节点的指针(Pointer)。

在这里插入图片描述

  • 由于不必按顺序存储,链表在插入数据的时候可以达到O(1)的复杂度,但是查找一个节点或者访问特定编号的节点则需要 O(n) 的时间。

  • 使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。

  • 在计算机科学中,链表作为一种基础的数据结构可以用来生成其它类型的数据结构。链表通常由一连串节点组成,每个节点包含任意的实例数据(data fields)和一或两个用来指向上一个/或下一个节点的位置的链接(links)。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的访问往往要在不同的排列顺序中转换。而链表是一种自我指示数据类型,因为它包含指向另一个相同类型的数据的指针(链接)。

  • 链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。

  • 链表通常可以衍生出循环链表,静态链表,双链表等。对于链表使用,灵活使用虚拟头结点可以简化问题。

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/385720.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C/C++大雪纷飞代码

目录 写在前面 C语言简介 EasyX简介 大雪纷飞 运行结果 写在后面 写在前面 本期博主给大家带来了C/C实现的大雪纷飞代码,一起来看看吧! 系列推荐 序号目录直达链接1爱心代码https://want595.blog.csdn.net/article/details/1363606842李峋同款跳…

大数据之数据湖

数据湖(Data Lake)是一个集中式存储库,用于存储大量的原始数据,包括结构化、半结构化和非结构化数据。这些数据可以以其原始格式存储,而不需要事先定义结构(即模式),这与传统的数据仓…

【STM32】STM32单片机入门

个人主页~ 这是一个新的系列,stm32单片机系列,资料都是从网上找的,主要参考江协科技还有正点原子以及csdn博客等资料,以一个一点没有接触过单片机但有一点编程基础的小白视角开始stm32单片机的学习,希望能对也没有学过…

昇思25天学习打卡营第3天|基础知识-数据集Dataset

目录 环境 环境 导包 数据集加载 数据集迭代 数据集常用操作 shuffle map batch 自定义数据集 可随机访问数据集 可迭代数据集 生成器 MindSpore提供基于Pipeline的数据引擎,通过数据集(Dataset)和数据变换(Transfor…

Kylin 入门教程

Apache Kylin 是一个开源的分布式数据仓库和 OLAP(在线分析处理)引擎,旨在提供亚秒级查询响应时间,即使在处理超大规模数据集时也是如此。Kylin 可以有效地将原始数据预计算为多维数据立方体(Cube),并利用这些预计算结果来提供快速查询。本文将带你从基础知识到操作实践…

构建大规模账号池与本地部署:GitHub爬虫项目详解

账号池搭建 必要性 常见登录方式: 基于Session Cookie的登录基于JWT的登录:登录生成JWT字符串 账号池存储cookie或者JWT字符串 方便后续发请求爬取数据 本地部署 conda建立一个虚拟环境 conda create -n new_env python3.x # 替换 x 为你需要的 P…

p28 vs环境-C语言实用调试技巧

int main() { int i0; for(i0;i<100;i) { printf("%d",i); } } 1.Debug 和Release的介绍 Debug通常称为调试版本&#xff0c;它包含调试信息&#xff0c;并且不做任何优化&#xff0c;便于程序员调试程序。 Release称为发布版本&#x…

MySQL数据库的DQL的高级数据查询语句

目录 非等值联查&#xff1a; 等值联查&#xff1a; eg&#xff1a;5张表联查 连接查询——left/right/inner join on eg: 连接查询——union Eg&#xff1a; 不去重的并集——union all 子查询&#xff08;内部查询&#xff09; 1、where型子查询 2、from型子查询&a…

Linux下git入门操作

0.创建仓库 可以按这个配置来&#xff0c;.gitignore中存放了上传时忽略的文件类型后缀。 1.clone仓库 在gitee上创建好仓库&#xff0c;点击克隆/下载&#xff0c; 复制地址fyehong/Linux_notes 。 在所需的文件夹中放置仓库。比如我在文件夹lesson9下存储仓库。就在less…

实验2-2-5 将x的平方赋值给y

#include <stdio.h> #include <math.h> int main(){int x3,y;printf("%d%d*%d\n",x*x,x,x);printf("%d*%d%d\n",x,x,x*x); }

【BUG】已解决:ERROR: Failed building wheel for jupyter-nbextensions-configurator

ERROR: Failed building wheel for jupyter-nbextensions-configurator 目录 ERROR: Failed building wheel for jupyter-nbextensions-configurator 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我…

华为诺亚发布无限上下文大模型,超越SoTA 4.3%

你的大语言模型是不是也患上了"长文健忘症"&#xff1f;当使用大模型遇到长上下文时总是会出现词不达意&#xff1f;别担心&#xff0c;LLM界的"记忆大师"来啦&#xff01;华为诺亚方舟实验室最新推出的EM-LLM模型&#xff0c;就像是给大模型装上了"超…

linux系统进程占cpu 100%解决步骤

1.查找进程 ps aux 查看指定进程: ps aux | grep process_name2.根据进程查找对应的主进程 pstree -p | grep process_name 3.查看主进程目录并删除 ps -axu | grep process_name rm -rf /usr/bin/2cbbb

数据库实验:SQL Server基本表单表查询

一、实验目的&#xff1a; 1、掌握使用SQL语法实现单表查询 二、实验内容&#xff1a; 1. 查询订购日期为2001年5月22日的订单情况。&#xff08;Orders&#xff09;&#xff08;时间日期的表达方式为 dOrderDate ‘2001-5-22’&#xff0c;类似字符串&#xff0c;使用单引号…

音视频入门基础:PCM专题(3)——使用Audacity工具分析PCM音频文件

音视频入门基础&#xff1a;PCM专题系列文章&#xff1a; 音视频入门基础&#xff1a;PCM专题&#xff08;1&#xff09;——使用FFmpeg命令生成PCM音频文件并播放 音视频入门基础&#xff1a;PCM专题&#xff08;2&#xff09;——使用Qt播放PCM音频文件 音视频入门基础&am…

从0开始搭建vue + flask 旅游景点数据分析系统(一):创建前端项目

根据前面的爬虫课程&#xff0c;我们重新开一个坑&#xff0c;就是基于爬取到的数据&#xff0c;搭建一个vueflask的前后端分离的数据分析系统 1 通过这个系列教程可以学习到什么&#xff1f; 从0开始搭建一个 vue flask 的数据分析系统&#xff1b;了解系统的整体架构&…

19.延迟队列优化

问题 前面所讲的延迟队列有一个不足之处&#xff0c;比如现在有一个需求需要延迟半个小时的消息&#xff0c;那么就只有添加一个新的队列。那就意味着&#xff0c;每新增一个不同时间需求&#xff0c;就会新创建一个队列。 解决方案 应该讲消息的时间不要跟队列绑定&#xf…

AI绘画入门实践 | Midjourney:使用 --chaos 给图像风格来点惊喜

在 Midjourney 中&#xff0c;--chaos 影响初始图像网格的多样性&#xff0c;指 MJ 每次出的4张图之间的差异性。 默认值为0&#xff0c;值越高&#xff0c;差异性越大。 使用格式&#xff1a;--chaos 0-100的整数值 使用演示 a lot of flowers --chaos 0 --v 6.0a lot of fl…

AOP~面向切面编程介绍

AOP基础 概述 AOP&#xff1a;Aspect Oriented Programming&#xff08;面向切面编程、面向方面编程&#xff09;&#xff0c;面向特定方法的编程。 动态代理是面向切面编程最主流的实现。 SpringAOP是Spring框架的高级技术&#xff0c;旨在管理bean对象的过程中&#xff0c…

C# datetimePicker

1. 直接把控件拉到设计器中&#xff0c;此时不要调整控件的values属性&#xff0c;这样就可以 打开后每次默认显示当天日期。 2. 属性Format long长日期格式默认值short短日期格式Time时间格式custom自定义时间格式在customFormat这个属性设置&#xff0c;比如yyyy-MM-dd HH…