经典面试题---环形链表

1. 环形链表1. - 力扣(LeetCode)

 

要解决这道题,我们首先要挖掘出带环的链表与不带环的链表之间的差别。

以此,才能设计出算法来体现这种差别并判断。

二者最突出的不同,就是不带环的链表有尾结点,也就是说在访问到某个结点时,其next指针可能为NULL。

而带环的链表则没有尾结点,负责访问链表的指针进入环以后,就会一直在环中转圈。

 但是,仅靠这个,我们很难解决这个问题。

按以上得到的信息来说,我们会尝试去1. 检查该链表是否有尾结点,或者2. 检查有无结点被重复访问

对于第一种思路,很明显行不通,因为在检查一个带环的链表时,我们会一直访问不到尾结点,但我们也无法找到确切的指标来证明该链表确实没有尾结点。

对于第二种思路,一般来说,我们会想到将已访问过的结点的地址保存起来,每访问一个结点,我们就检查已保存的地址中是否有与新结点地址相同的地址。

第二种思路没有任何问题,确实可以顺利解决这个问题,那么我们来看看进阶要求。

很明显,第二种思路写出的算法的时间复杂度为O(n!),空间复杂度为O(n)。

也就是说还有更妙的办法,或者说带环链表和不带环链表之间还有更加值得利用的区别。

仔细观察就能发现,带环会改变环中结点之间的相对关系。

当链表不带环时,我们可以肯定地说:值为2的结点在值为-4的结点之前。

但是,当链表带环时,我们却可以认为值为-4的结点在值为2的结点之前,因为值为-4的结点的next指针指向的是值为2的结点。

也就是说,带环改变了环中结点之间的前后相对关系。

那么,我们如何使得这种差异体现出来呢?

这使得我们想到快慢指针

假设快慢指针的都从头结点开始移动。

当链表不带环时,快慢指针一旦分开便再无相遇的可能;

当链表带环时,由于环中结点的相对关系被改变,在快慢指针都进入环之后,原本在前的快指针可以认为是在慢指针之后,那么快指针就会不断追击慢指针,最终二者可能相遇。

但是,我们如何确保快指针最后一定会追上慢指针呢?

在追击过程中,二者每次移动,它们之间的距离的减少量就是二者的速度之差。

由于在慢指针刚进入环时,二者之间的距离一定为整数,所以当二者的速度之差为1时,它们就必定相遇。

依据此思路,我们可以设计出如下的算法:

typedef struct ListNode ListNode;bool hasCycle(struct ListNode *head) {ListNode* slow = head;ListNode* fast = head;while(fast && (fast->next)){fast = fast->next->next;slow = slow->next;if(fast == slow)return true;}return false;
}

很明显,该算法的时间复杂度为O(n),空间复杂度只有O(1),满足的进阶的要求并明显减小了时间复杂度。

2. 数学分析

完成这道题还不足以让你通过面试,接下来面试官可能会问你:

1. 二者为什么一定会相遇呢?

2. 慢指针每次前进一个结点,快指针每次前进三个结点可以吗?四或五个结点呢?

 第一个问题我们在解题的过程中就已经解决,你只要将思路清晰地阐述即可。

对于第二个问题,要让面试官刮目相看,我们自然不满足于只解决给出的三种情况(对具体情况单独分析也挺麻烦的),我们会尝试给出判断可行的数学公式。

我们假设:

1. 环的周长为c(环有c个结点)。

2. 当慢指针刚进入环时,快指针已经在环中移动的长度为L。

3. 快指针的速度为k(每次移动k个结点)。

4. 慢指针进入环之后,移动n次时与快指针相遇。

 将进入环的第一个结点标记为下标0,随后结点的下标依次递增,直到再次遇到下标为零的结点。

 二者相遇时,快慢指针的位置是相同的。

据此,当二者相遇时,一定满足这个表达式:(nk + L) % c = n % c

假设相遇时,快指针比慢指针多走了m圈,则有:nk + L = n + mc

移项可得:n = (mc - L) / (k - 1)

由于n为整数,所以,如果存在m使得(mc - L) % (k - 1) = 0,我们就可以认为二者一定会相遇。

很明显,当k = 2时,上式一定成立(任何整数都可以整除1),这也就验证了我们之前的结论。

而当k > 2时,上式能否成立则受到c与L的影响,无法保证一定成立。

3. 环形链表2. - 力扣(LeetCode)

 也就是在刚才的基础之上,要求我们求出环中的第一个结点。

这个时候,我们之前想到的第一种思路似乎就能派上用场了:如果找到了重复访问的结点,直接返回该结点的地址即可。

但是,这道题依然有同样的进阶要求:

同样的要求,也就是在提示我们这道题的最佳思路一定是建立在第一题的解法之上。

那么在第一题判断该链表有环之后,我们要如何找到环中第一个结点呢?

不妨先考虑一下,当快慢指针相遇时,二者在哪个位置。

当慢指针刚好进入环时,快指针的坐标为L % c。

按照快指针追击慢指针的角度来看,快慢指针之间相距的距离为c - (L % c)。

每移动一次,二者之间的距离会缩短1,那么二者共会移动c - (L % c)次。

所以,最终慢指针的坐标会停留在c - (L % c)处,也即二者相遇时的坐标。

此时,慢指针要再次到达下标为0的结点(环中第一个结点),需要再移动(L % c)次。

注意到,L = (L % c) + xc(x为整数)。

也就是说,让慢指针移动L次,其也依然会到达下标为0处(多绕x圈)。

可是,此时,我们怎么知道L是多少呢?

仔细观察会发现,头结点到环中第一个结点的距离恰好就是L。

因为快指针的速度是慢指针的两倍,所以,在进环之前,头结点到慢指针的距离与慢指针到快指针的距离是相等的。

在慢指针恰好进入环时,头结点到环中第一个结点的距离就等于慢指针到快指针的距离,即L。

所以,我们只需要让头结点处的指针和相遇处的指针同时开始移动(每次一个结点),最终就会在下标为0的结点处相遇。

依据这个思路,我们可以写出如下代码:

typedef struct ListNode ListNode;struct ListNode *detectCycle(struct ListNode *head) {ListNode* slow = head;ListNode* fast = head;while(fast && (fast->next)){fast = fast->next->next;slow = slow->next;if(fast == slow){ListNode* meet = slow;while(meet != head){meet = meet->next;head = head->next;}return meet;}}return NULL;
}

4. 结语

如果你在面试中遇到了这道题并清晰流畅地答出了本文的内容,那么你的面试就稳了一半了。

如果觉得写的不错就三连支持一下吧!

加纳……

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

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

相关文章

数据库数据恢复—SQL Server数据库ndf文件变为0KB的数据恢复案例

SQL Server数据库故障: 存储设备损坏导致存储中SQL Server数据库崩溃。对数据库文件进行恢复后,用户发现有4个ndf文件的大小变为0KB。该SQL Server数据库每10天生成一个大小相同的NDF文件,该SQL Server数据库包含两个LDF文件。 SQL Server数据…

头歌实践教学平台:CG1-v2.0-直线绘制

第4关:直线光栅化-任意斜率的Bresenham画线算法 一.任务描述 1.本关任务 (1)根据直线Bresenham算法补全line函数以绘制白色直线,其中直线斜率为任意情况。 (2)当直线方程恰好经过P(x,y)和T(x,y1)的中点M时,统一选取直线上方的T点为显示的像…

云效 Pipeline as Code 来了!这些场景,用好它效率翻倍!

从可视化编排到支持 YAML 编排 云效流水线 Flow 是开箱即用的企业级持续集成和持续交付工具,支持丰富的代码源、构建、自动化测试工具、多种部署类型和部署方式,与阿里云深度集成,还提供多种企业级特性,助力企业高效完成从开发到…

PTP 对时协议 IEEE1588 网络对时 计算原理

前言 本文将阐述 PTP 对时协议的原理,slave 节点如何根据获取的时间来纠正和更新自己的时间。 协议概述 整个通讯过程中会发送 4 种类型的数据包,用来支撑对时。下面是 4 个包的解释 Sync message: 由 master 发送,发起对时事务, slave 接…

《ElementUI 基础知识》el-tree 之“我的电脑”目录结构效果

前言 项目需求,Web 端获取服务器文件夹目录结构。目录数据是调接口获取,本篇略过,直接展现数据! 效果 实现 html 代码 8 - 15 行,自定义节点信息;代码 9 - 14 行,判断 icon 显示&#xff1b…

通过物联网管理多台MQTT设备-基于米尔T527开发板

本篇测评由电子工程世界的优秀测评者“JerryZhen”提供。 本文将介绍基于米尔电子MYD-LT527开发板的网关方案测试。 一、系统概述 基于米尔-全志 T527设计一个简易的物联网网关,该网关能够管理多台MQTT设备,通过MQTT协议对设备进行读写操作,…

前端框架-echarts

Echarts 项目中要使用到echarts框架&#xff0c;从零开始在csdn上记笔记。 这是一个基础的代码&#xff0c;小白入门看一下 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" co…

x6.js bug记录-流程图json数据导入进来之后拖拽节点,节点直接飞走了

添加josn数据进来之后虽然能正常渲染&#xff0c;但是只要一拖拽&#xff0c;则节点就直接飞走了&#xff0c;看不到了。 找了一下午的问题&#xff0c;最后发现。保存的json坐标位置是字符串类型&#xff0c;而这边的位置必须是数字类型。如下&#xff1a; {position: { x: &…

关于vs2019 c++ STL 中容器的迭代器的 -> 运算符的使用,以 list 双向链表为例

&#xff08;1&#xff09;如下的结构体 A &#xff0c;若有指针 p new A() &#xff1b;则可以使用 p->m &#xff0c; p->n 解引用运算符。 struct A { int m ; int n; } 对于 STL 中提供的迭代器&#xff0c;提供了类似于指针的功能。对迭代器也可以使用 -> 运算…

RS3236-ADJ8YF5功能和参数介绍及PDF资料

RS3236-ADJ8YF5功能和参数介绍及PDF资料-公司新闻-配芯易-深圳市亚泰盈科电子有限公司 品牌: RUNIC(润石) 封装: SOT-23-5 描述: 输出电压可调(参考电压0.81V),Iout500mA(Max),Vin7.5V(Max),带过温保护 输出类型: 可调 最大输入电压: 7.5V 输出电压: 810mV~6.6V 最大输出电流…

订单超时自动取消的实践方案

1、定时任务方案 方案流程&#xff1a; 每隔 30 秒查询数据库&#xff0c;取出最近的 N 条未支付的订单。 遍历查询出来的订单列表&#xff0c;判断当前时间减去订单的创建时间是否超过了支付超时时间&#xff0c;如果超时则对该订单执行取消操作。 定时任务方案工程实现相…

QT--5

1> 将网络聊天室重新实现一遍 服务器端 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);ser new QTcpServer(this); }Widget::~Widget() {delete ui; }vo…

IDEA 好用的插件

图标插件&#xff1a;Atom Material Icons 此插件的作用就是更好的显示各种文件的类别&#xff0c;使之一目了然 汉化包 Chinese ​(Simplified)​ Language Pack / 中文语言包 作用就是 汉化 AI编码助手 GitHub Copilot AI编码助手&#xff1a;提示代码很好用 缺点&#xff1a…

八款免费好用的3D建模AI工具,让你的设计更简单!

随着人工智能和大语言模型的不断发展&#xff0c;AI工具正逐渐渗透到3D建模领域中。传统上&#xff0c;3D建模师需使用如3ds Max、Maya等这类复杂的3D建模软件&#xff0c;投入大量的时间与精力来创作精细的模型。然而&#xff0c;有了AI工具的辅助&#xff0c;设计过程不仅对专…

json返回工具类|世界协调时间(UTC)

一、问题 世界协调时间&#xff08;UTC&#xff09;是一个标准的时间参考&#xff0c;通常被用于跨越不同时区的时间标准。要将 UTC 时间转换为中国时间&#xff08;中国标准时间&#xff09;&#xff0c;你需要将时间加上8个小时&#xff0c;因为中国位于 UTC8 时区。 初中知…

时尚圈的节制美学 — 奥柔拉 AVRALA的独特设计理念

在这个多元化的时代&#xff0c;女性正在经历一场前所未有的角色变革。她们不再仅仅满足于传统的社会角色&#xff0c;而是勇敢地追求个人职业发展和自我实现。在这样的背景下&#xff0c;服饰不仅仅是外在的装饰&#xff0c;更是内心故事的讲述者、个性自我的表达者、身份归属…

【go项目01_学习记录10】

操作数据库 1 插入数据2 显示文章2.1 修改 articlesShowHandler() 函数2.2 代码解析 3 编辑文章3.1 添加路由3.2 编辑articlesEditHandler()3.3 新建 edit 模板3.4 代码重构3.5 完善articlesUpdateHandler()3.6 测试更新3.7 封装表单验证 1 插入数据 . . . func articlesStore…

扩展学习|本体研究进展

文献来源&#xff1a; 王向前,张宝隆,李慧宗.本体研究综述[J].情报杂志,2016,35(06):163-170. 一、本体的定义 本体概念被引入人工智能、知识工程等领域后被赋予了新的含义。然而不同的专家学者对本体的理解不同,所给出的定义也有所差异。 人工智能领域的学者Neches(1991)等人对…

苹果新款 M4 芯片专注于 AI

爆炸性消息&#xff01;苹果的新一代 M4 芯片来了&#xff01;这家伙拥有 38 万亿次操作的超强神经引擎&#xff0c;速度比苹果 A11 芯片的 NPU 快 60 倍&#xff01;虽然它的速度还没有达到 Snapdragon X Elite 的 45 TOPS&#xff0c;但苹果自夸 M4 将提供与最新 PC 芯片相同…

QT-TCP通信

网上的资料太过于书面化&#xff0c;所以看起来有的让人云里雾里&#xff0c;看不懂C-tcpsockt和S-tcpsocket的关系 所以我稍微画了一下草图帮助大家理解两个套接字之间的关系。字迹有的飘逸勉强看看 下面是代码 服务端&#xff1a; MainWindow::MainWindow(QWidget *parent) …