当前位置: 首页 > news >正文

【数据结构与算法 刷题系列】求带环链表的入环节点(图文详解)

             💓 博客主页:倔强的石头的CSDN主页 

             📝Gitee主页:倔强的石头的gitee主页

   ⏩ 文章专栏:《数据结构与算法 经典例题》C语言

                                  期待您的关注

1b7335aca73b41609b7f05d1d366f476.gif

目录

一、问题描述

二、解题思路

方法一:数学公式推导法

方法二:转换为相交链表问题求解

三、代码实现

方法一实现代码

方法二实现代码


一、问题描述

原题链接   142. 环形链表 II - 力扣(Le142. 环形链表 II - 力扣(Le

二、解题思路

方法一:数学公式推导法

预备知识

此方法的数学推导建立在判断链表是否带环的基础算法上,推荐阅读前置文章

点击下方文字

【数据结构与算法 刷题系列】判断链表是否有环-CSDN博客

 如图,通过快慢指针法得到两个指针相遇位置时

假设:

  • 链表入环前的长度为L
  • 环的长度为C
  • 快慢指针相遇节点为meet
  • 环的入口与相遇节点meet的距离为N
  • 相遇时,快指针已经在环内走了X圈(X>=1,快指针至少比慢指针都走一圈才能追上)
推导过程:

在meet相遇点

慢指针移动距离为L+N

快指针移动距离为L+X*C+N

 

另外,快指针移动距离是快指针的两倍

快指针也可以写成2(L+N)

将两条公式结合起来

2(L+N)=L+X*C+N

化简

L+N=X*C

L=X*C-N

L=(X-1)*C+C-N    

 最终得到的公式:

L=(X-1)*C+C-N    

该公式在图中说明的问题:

链表入环前的长度L

与相遇点到环入口的距离再加(X-1)圈      ——X最少为1,所以X-1至少为0

是相等的

结论:

如果两个指针分别从链表起始位置和相遇点meet开始移动,那么两个指针第一次相遇的节点就是环的入口

方法二:转换为相交链表问题求解

此方法的数学推到建立在判断链表是否带环的基础算法上,推荐阅读

【数据结构与算法 刷题系列】相交链表-CSDN博客

该方法是将带环链表问题转换为相交链表问题,将问题降级处理

 首先,依然要 求得快慢指针相遇交点

然后将取得该节点下一个节点地址,令其成为一个单独链表的首节点,断开链表 

 之后,这个问题就可以转换为相交链表问题来解决

 

三、代码实现

方法一实现代码

struct ListNode {int val;struct ListNode* next;};
typedef struct ListNode ListNode;//方法一:数学推理法
struct ListNode* detectCycle1(struct ListNode* head)
{ListNode* slow, * fast;slow = fast = head;ListNode* meet = NULL;while (fast && fast->next){slow = slow->next;fast = fast->next->next;if (slow == fast)//先求得快慢指针相遇节点{meet = slow;while (meet != head)//两指针同时移动,相遇即是入口{meet = meet->next;head = head->next;}return meet;}}return NULL;
}

方法二实现代码

//求相交链表的交点的函数
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB)
{ListNode* pcurA = headA;ListNode* pcurB = headB;int countA = 0;int countB = 0;while (pcurA)//求出链表长度{pcurA = pcurA->next;countA++;}while (pcurB){pcurB = pcurB->next;countB++;}int tmp = abs(countA - countB);//长度差值ListNode* slow, * fast;if (countA < countB){slow = headA;fast = headB;}else{slow = headB;fast = headA;}while (tmp--)//长链表先走差值的步数{fast = fast->next;}while (fast && slow)//同步比较{if (fast == slow)return fast;fast = fast->next;slow = slow->next;}return NULL;
}
struct ListNode* detectCycle(struct ListNode* head)
{ListNode* slow, * fast;slow = fast = head;ListNode* meet = NULL;while (fast && fast->next){slow = slow->next;fast = fast->next->next;if (slow == fast)//先求得快慢指针相遇节点{meet = slow;ListNode* newhead = meet->next;meet->next = NULL;//将环断开,变成两个相交的链表return getIntersectionNode(head, newhead);}}return NULL;
}

总结

两种方法可以自行选用
第一种方法属于推理复杂,代码简单

第二种方法属于推理简单,代码实现细节复杂

可根据实际情况选择合适的方法

http://www.lryc.cn/news/375061.html

相关文章:

  • 独立游戏之路:Tap篇 -- Unity 集成 TapTap 广告详细步骤
  • 设计灵感源泉!7个令人赞叹的网页界面设计展示
  • vivado PIN
  • docker部署mysql+nginx+redis
  • python文件操作、文件操作、读写文件、写模式
  • 【亲测可用】docker进入正在运行的容器
  • 线程池吞掉异常的case:源码阅读与解决方法
  • 基于mysqlbinlog恢复数据
  • Android_Android Studio 常用快捷键 for mac
  • [EFI]NUC11电脑 Hackintosh 黑苹果efi引导文件
  • 在Ubuntu上配置和设置防火墙UFW
  • nginx安装环境部署(完整步骤)
  • 如何做电子骑缝章?
  • 2024.6.13 bailuo-Docker 安装与镜像拉取
  • 【Java开发规范】IDEA 设置 text file encoding 为 UTF-8,且文件的换行符使用 Unix 格式
  • 使用`LD_PRELOAD`和`jemalloc`实现C/C++信号的内存堆栈信息收集
  • 计算机组成原理(四)Cache存储器
  • 怎么做成的文件二维码?扫阅览文件的制作方法
  • js 前端 Function.prototype.call.call(0[‘toString‘], *, 16)
  • 李沐:用随机梯度下降来优化人生!
  • Linux 环境.Net程序堆栈查询
  • 志愿服务管理系统的设计
  • 微信小游戏5月畅销榜,新老产品更替显著,亿级爆款频出
  • 自己想要公开自己的学习方法,但是自己很害怕自己的学习方法是一个错误的,因为对于自己而言,专升本的机会只有一次
  • linux centos consul1.15.2一键安装部署
  • 速盾:dns和cdn区别?
  • 多目标跟踪中用到的求解线性分配问题(Linear Assignment Problem,LAP)C++
  • Unity | Shader基础知识(第十四集:简单效果练习)
  • Vue48-ref属性
  • 【SpringCloud学习笔记】RabbitMQ(中)