【C语言手撕算法】LeetCode-142. 环形链表 II(C语言)

【C语言手撕算法】LeetCode-142. 环形链表 II(C语言)

【C语言手撕算法】LeetCode-142. 环形链表 II(C语言)

前言:
本专栏将给大家带来一些有意思的算法题
希望对大家有所帮助
若内容对大家有所帮助,可以收藏慢慢看,感谢大家支持!!!
谢谢大家 ! ! !

一、题目介绍

本篇是小编从leetcode上挑选的一道例题
同时,还是一道难度较大的面试题
就让我们来手撕这道面试题吧

下面是题目链接:

LeetCode-142. 环形链表 II

在这里插入图片描述

二、题目详解

1.审题

老规矩,拿到题目先审题,题目要求返回链表开始入环的第一个节点
所以,首先我们要判断该链表是否为环形链表,如果不是,那直接返回NULL就行了
若是环形链表该想办法找出返回链表开始入环的第一个节点

下面我一步一步带大家解出此题

2.判断是否为环形链表

(1)思路

如果链表不为环形链表,遍历链表就一定会走到空指针
但是如果是环形链表,遍历将会陷入死循环
总不能等到遍历死循环后再来判断是环形链表吧

这时候我想到了龟兔赛跑的故事
我们可以用一个快指针,一个慢指针来遍历链表
一个每次走2步,一个每次走1步,这样快指针每次就一定会比慢指针快一步

如果是环形链表:那个快指针就一定会先入环,当慢指针也入环后,快指针就会在环中一步一步追上慢指针
如果链表不为环形链表:快指针也无法再次与慢指针相遇,之后就一定会走到空指针

(2)代码演示

这里先创建快慢指针
然后用一个while循环,当fast走到NULL时结束
且当fast==slow时说明已经相遇,是环形链表,接着就只要找入环节点就行了

代码演示:

structListNode*detectCycle(structListNode*head){structListNode*fast=head;//快指针structListNode*slow=head;//慢指针while(fast&&fast->next){ fast=fast->next->next;//每次走2步 slow=slow->next;//每次走一步if(fast==slow)//相等就代表相遇{//F函数为找到入环节点函数(后面会讲)returnF(head,fast);}}//当指针走到空指针就说明不是环形链表,返回NULLreturnNULL;}

3.找到入环节点

(1)思路

现在已知是环形链表,那该怎么找到入环节点呢?

这里为了方便理解,画了一张草图
大家在做算法题的时候也应该多多画图,能更好的理解题目意思

首先设环的长度为C
设非环的长度为L
设相遇点与入环节点的距离为N
在这里插入图片描述
我们还可以写出fastslow走的总距离:
L ( fast ) = L + N + x * C (x为fast走的圈数)

于fast比slow快,所以slow不可能走完一整圈环,走到一半就会被追上,所以有:
L ( slow ) = L + N
又因为fast的速度是slow的两倍,于是就有L ( fast ) = 2*L ( slow )
带入得:L + N + x * C = 2 * ( L + N )
化简得:x * C = N + L
变式得:( x - 1 ) * C + C - N = L
其中,左式相当于一指针走了(x-1)圈再加上C-N(图上标出了)
而右式就是头节点到入环节点的距离

所以 ! ! !
我们让一个指针meet从fast与slow的相遇点开始走,让一个指针cur从头节点开始走
当meet在环内走了(x-1)圈时,再走C-N距离就会与走了L距离的cur相遇

(2)代码演示

这里先创建meetcur,分别从相遇点和头节点开始以相同速度走
此时meetcur的相遇点就是入环节点
structListNode*F(structListNode*head,structListNode*meet){structListNode*cur=head;while(1)//一定会找到,故用死循环,找到时就跳出循环{if(meet==cur){//此时找到,任意返回一个值就行return meet;} meet=meet->next; cur=cur->next;}}

三、考考大家

OK,本文【C语言手撕算法】LeetCode-142. 环形链表 II(C语言)到这里就结束了

但小编在这里给大家留下一个思考问题:
当慢指针的速度为 1 ,而快指针的速度为 3,4, 5…n 时,两指针还会相遇吗?
有没有可能两人错过呢?大家可以去思考思考。

结语

本期资料来自于:


https://leetcode.cn/

OK,本期的【C语言手撕算法】到这里就结束了

若内容对大家有所帮助,可以收藏慢慢看,感谢大家支持

本文有若有不足之处,希望各位兄弟们能给出宝贵的意见。谢谢大家!!!

新人,本期制作不易希望各位兄弟们能动动小手,三连走一走!!!

支持一下(三连必回QwQ)

Read more

C++入门看这一篇就够了——超详细讲解(120000多字详细讲解,涵盖C++大量知识)

C++入门看这一篇就够了——超详细讲解(120000多字详细讲解,涵盖C++大量知识)

目录 一、面向对象的思想 二、类的使用 1.类的构成 2.类的设计 三、对象的基本使用 四、类的构造函数 1.构造函数的作用 2.构造函数的特点 3.默认构造函数 3.1.合成的默认构造函数 3.2.手动定义的默认构造函数 四、自定义的重载构造函数 五、拷贝构造函数 1.手动定义的拷贝构造函数 2.合成的拷贝构造函数 3.什么时候调用拷贝构造函数 六、赋值构造函数 七、析构函数 八、this指针 九、类文件的分离 十、静态数据 1.静态数据成员 2.静态成员函数 十一、

By Ne0inhk
【C++:异常】C++ 异常处理完全指南:从理论到实践,深入理解栈展开与最佳实践

【C++:异常】C++ 异常处理完全指南:从理论到实践,深入理解栈展开与最佳实践

🎬 个人主页:艾莉丝努力练剑 ❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》 《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》 ⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平 🎬 艾莉丝的简介: 🎬 艾莉丝的C++专栏简介: 文章目录 * C++学习阶段的三个参考文档 * 1 ~> 异常的概念 * 2 ~> 异常的使用层 * 2.1 异常的抛出和捕获 * 2.2 栈展开 * 2.2.1 理论 * 2.2.2 最佳实践 * 2.3 查找匹配的处理代码 * 2.3.

By Ne0inhk
季节-趋势分解(STL)方法详解

季节-趋势分解(STL)方法详解

季节-趋势分解(STL)方法详解 在分析时间序列数据时,我们经常需要理解数据中隐藏的规律。比如零售商想知道销售额的增长是真实的业务增长还是仅仅是季节性因素,气候学家需要从温度数据中分离出长期变暖趋势和正常的季节变化,这些都需要一种强大的分解方法。STL(Seasonal and Trend decomposition using Loess)正是为此而生的统计方法,它能够将复杂的时间序列数据优雅地分解为三个易于理解的组成部分:趋势、季节性和余项。 数学原理与核心思想 STL的核心思想非常直观:任何时间序列都可以表示为三个加法组成部分的和。用数学公式表达就是: Yν=Tν+Sν+RνY_\nu = T_\nu + S_\nu + R_\nuYν =Tν +Sν +Rν 其中YνY_\nuYν 代表在时间ν\nuν的观测值,TνT_\nuTν 是趋势分量,SνS_\nuSν 是季节分量,RνR_\nuRν 是余项分量。

By Ne0inhk
C++ 继承入门(上):从基础概念定义到默认成员函数,吃透类复用的核心逻辑

C++ 继承入门(上):从基础概念定义到默认成员函数,吃透类复用的核心逻辑

🔥小叶-duck:个人主页 ❄️个人专栏:《Data-Structure-Learning》 《C++入门到进阶&自我学习过程记录》《算法题讲解指南》--从优选到贪心 ✨未择之路,不须回头 已择之路,纵是荆棘遍野,亦作花海遨游 目录 前言 一. 继承的概念与定义   1、继承的核心概念   2、继承的定义格式   3、继承方式与成员访问权限 二. 基类与派生类的转换:子类对象能当父类用吗? 三. 继承中的作用域:同名成员会冲突吗?   1、变量隐藏   2、函数隐藏 四、派生类的默认成员函数:构造、拷贝、析构怎么写?   1、构造函数:先调用父类构造,再初始化子类成员   2、拷贝构造:先拷贝父类,再拷贝子类   3、 赋值重载:

By Ne0inhk