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

Leetcode 31

1 题目

142. 环形链表 II

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

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

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

提示:

  • 链表中节点的数目范围在范围 [0, 104] 内
  • -105 <= Node.val <= 105
  • pos 的值为 -1 或者链表中的一个有效索引

2 思路

实际上这是141. 环形链表 - 力扣(LeetCode)的进阶版

1 首先判断是否有环(可以按照easy的策略,快慢指针相遇)

2 返回环节点,按照图中的路径,其实是一点数学呢,相遇以后,其中一个指针到头节点,快慢指针以相同速度前进,再次项羽点就是环节点

3 注意非空,注意临界条件

3 代码实现(c)

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head) {ListNode *one = head ;ListNode *two = head;while(one != NULL && one-> next != NULL){one = one -> next -> next ;two = two -> next ;if(one == two){two = head ;while(one != two){one = one -> next;two = two -> next;} return one ;   }} return NULL;}

初版,失败的代码()

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head) {ListNode *one = head->next;ListNode *two = head;while(one != NULL){one = one -> next ;//一开始是想让one,two做两个小跟班,实际上逻辑行不通two = two -> next ;if(one == two){two = head ;while(one != two){one = one -> next;two = two -> next;if(one == two){break;} }return one;}}return NULL;}

代码中的问题

  1. 初始指针位置错误代码中初始化为 one = head->next; two = head;,若链表为空(head == NULL),会直接访问 head->next 导致空指针异常。

  2. 快慢指针步长错误检测环时,快指针应每次走 2 步,慢指针每次走 1 步(才能利用 “相对速度” 相遇)。但代码中 one(快指针)和 two(慢指针)每次都只走 1 步(one = one->next; two = two->next;),相当于两个指针同速前进,若有环也可能永远不相遇。

正确的环起始节点检测逻辑

要找到环的起始节点,核心利用快慢指针相遇的性质

  1. 检测环是否存在:快指针(每次 2 步)和慢指针(每次 1 步)从表头出发,若相遇则有环;若快指针走到终点(NULL)则无环。

  2. 找到环的起始节点:当快慢指针相遇时,将其中一个指针重置到表头,两者以相同速度(每次 1 步)前进,再次相遇的节点就是环的起始节点。

    原理:设表头到环起点距离为 a,环起点到相遇点距离为 b,环长度为 c。相遇时快指针走了 a + b + k*ck 为圈数),慢指针走了 a + b。由于快指针速度是慢指针的 2 倍,因此 a + b + k*c = 2*(a + b),化简得 a = k*c - b,即表头到环起点的距离 = 相遇点到环起点的距离(绕环 k-1 圈后)。因此两指针同速前进时,会在环起点相遇。

修正后的代码(示例)

struct ListNode *detectCycle(struct ListNode *head) {if (head == NULL || head->next == NULL) {return NULL; // 空链表或只有一个节点,无环}ListNode *slow = head;ListNode *fast = head;// 第一步:检测环是否存在(快慢指针相遇)while (fast != NULL && fast->next != NULL) {slow = slow->next;       // 慢指针走1步fast = fast->next->next; // 快指针走2步if (slow == fast) {      // 相遇,有环// 第二步:找环的起始节点slow = head;         // 慢指针重置到表头while (slow != fast) {slow = slow->next;fast = fast->next; // 同速前进,再次相遇即为环起点}return slow;}}return NULL; // 无环
}

总结

  • 原代码因指针初始位置和步长错误,无法正确检测环和起始节点。
  • 正确逻辑需利用快慢指针的 “2 倍速差” 相遇检测环,再通过重置指针同速前进找到环起点。
http://www.dtcms.com/a/516527.html

相关文章:

  • 手机 iOS 系统全解析,生态优势、开发机制与跨平台应用上架实践指南
  • 在线做动漫图的网站网站开发用什么技术asp
  • React Native 使用 react-native-credentials-manager 接入谷歌登录教程
  • 从零起步学习MySQL || 第七章:初识索引底层运用及性能优化(结合底层数据结构讲解)
  • CVPR2025 | OPS | 通过假设空间增强提升对抗迁移性
  • 自己做的网站怎么才能在百度上查找郑州定制网站推广工具产品
  • 如何从小白变成rust糕手
  • 注册一个网站多少钱?哪个网站可以免费建站
  • GCC与Makefile常用基础知识
  • 类装饰器
  • 什么网站可以直接做word如何在外管局网站做付汇延期
  • Dify从入门到精通 第22天 利用分支与判断构建智能路由客服机器人
  • 网站底备案号链接代码商丘建设厅网站首页
  • 【C++】手搓AVL树
  • 【完整源码+数据集+部署教程】【天线&其他】月球表面状况检测系统源码&数据集全套:改进yolo11-unireplknet
  • Flutter---弹窗
  • 从零开始学习RabbitMQ
  • 台州市住房和城乡建设局网站做美容美发学校网站公司
  • [答疑]考虑复用,尺度应该怎样把握
  • 注册网站借钱平台犯不犯法个人网站logo需要备案吗
  • 最新电大网站开发维护竞价托管推广代运营
  • 字符串统计
  • Docker与Tomcat:一键部署Java Web应用的完美组合
  • 【同步/异步 日志系统】 --- 前置技术
  • 图论基础和表示
  • 网站建设为了什么怎么看网站谁做的
  • [小白]spring boot接入emqx
  • Spring Boot 实现GZIP压缩优化
  • Spring Boot使用Redis实现消息队列
  • 互联网大厂Java面试实战:以Spring Boot与微服务为核心的技术场景剖析