解密链表环的起点:LeetCode 142 题

解密链表环的起点:LeetCode 142 题

解密链表环的起点:LeetCode 142 题

视频地址

因为想更好的为大佬服务,制作了同步视频,这是Bilibili的视频地址

🌟 引言

链表环检测问题在C++中同样是一个经典面试题。本文将用C++实现LeetCode 142题"环形链表II"的解决方案,深入讲解快慢指针算法的原理和实现细节。

🔍 问题描述

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

🧠 解题思路回顾

快慢指针算法

  1. 使用两个指针:slow每次走一步,fast每次走两步
  2. 如果两指针相遇,说明链表有环
  3. 将其中一个指针重置到链表头,然后两指针以相同速度前进
  4. 再次相遇的位置就是环的起点

数学原理

设:

  • 链表头到环起点距离:a
  • 环起点到相遇点距离:b
  • 相遇点到环起点距离:c

则有:

  • 第一次相遇时:slow走了a+bfast走了a+b+c+b
  • 因为fast速度是slow的两倍:2(a+b) = a+2b+c
  • 推导得:a = c

💻 C++代码实现

/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */classSolution{public: ListNode *detectCycle(ListNode *head){// 边界条件处理if(head ==nullptr|| head->next ==nullptr){returnnullptr;} ListNode *slow = head; ListNode *fast = head;// 第一阶段:检测是否有环while(fast !=nullptr&& fast->next !=nullptr){ slow = slow->next; fast = fast->next->next;if(slow == fast){break;// 相遇说明有环}}// 检查是否因为无环退出循环if(fast ==nullptr|| fast->next ==nullptr){returnnullptr;}// 第二阶段:寻找环起点 slow = head;// 重置慢指针到头部while(slow != fast){ slow = slow->next; fast = fast->next;}return slow;// 相遇点即为环起点}};

🛠 代码解析

数据结构定义

structListNode{int val; ListNode *next;ListNode(int x):val(x),next(NULL){}};

这是LeetCode标准的链表节点定义,包含一个整数值和指向下一个节点的指针。

算法实现细节

寻找环起点

slow = head;// 重置慢指针到头部while(slow != fast){ slow = slow->next; fast = fast->next;}

根据数学推导,两指针以相同速度前进,再次相遇点即为环起点。

无环检查

if(fast ==nullptr|| fast->next ==nullptr){returnnullptr;}

如果因为快指针无法前进而退出循环,说明无环。

环检测阶段

while(fast !=nullptr&& fast->next !=nullptr){ slow = slow->next; fast = fast->next->next;if(slow == fast){break;// 相遇说明有环}}

快指针每次走两步,慢指针每次走一步,直到相遇或快指针无法前进。

指针初始化

ListNode *slow = head; ListNode *fast = head;

快慢指针都从头节点开始。

边界条件处理

if(head ==nullptr|| head->next ==nullptr){returnnullptr;}

处理空链表或单节点链表的特殊情况。

🚀 性能分析

  • 时间复杂度:O(n)
    • 最坏情况下需要遍历链表两次
  • 空间复杂度:O(1)
    • 只使用了固定数量的指针变量

🐞 常见问题与调试

常见错误

  1. 初始条件处理
    忘记处理空链表或单节点链表的情况。
  2. 指针重置错误
    在第二阶段错误地重置了快指针而不是慢指针。

空指针访问

while(fast !=nullptr&& fast->next !=nullptr)

必须同时检查fastfast->next,否则可能访问空指针的next成员。

调试技巧

  1. 小规模测试
    • 无环链表:1->2->3->null
    • 有环链表:1->2->3->4->2(环在节点2)
  2. 边界测试
    • 空链表
    • 单节点自环链表
    • 双节点互相指向的链表

打印指针地址

cout <<"Slow: "<< slow <<" Fast: "<< fast << endl;

帮助跟踪指针移动情况。

📊 复杂度对比表

方法时间复杂度空间复杂度适用场景
哈希表法O(n)O(n)需要简单实现时
快慢指针O(n)O(1)需要节省空间时

🌈 总结

通过C++实现的快慢指针算法,我们能够高效地解决链表环检测问题。关键在于:

  1. 理解快慢指针相遇的数学原理
  2. 正确处理边界条件和指针访问

分两个阶段实现:环检测和环起点定位

解密链表环的起点:LeetCode 142 题

这种方法不仅高效(O(n)时间,O(1)空间),而且体现了算法设计的巧妙之处。掌握这个技巧,你就能轻松应对链表相关的各种环检测问题了!

Read more

Flutter for OpenHarmony: Flutter 三方库 mongo_dart 助力鸿蒙应用直连 NoSQL 数据库构建高效的数据流转系统(纯 Dart 驱动方案)

Flutter for OpenHarmony: Flutter 三方库 mongo_dart 助力鸿蒙应用直连 NoSQL 数据库构建高效的数据流转系统(纯 Dart 驱动方案)

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 在进行 OpenHarmony 的工业巡检、内部管理系统或边缘计算(Edge Computing)应用开发时,有时我们需要鸿蒙前端应用直接与后端的 MongoDB 数据库进行交互,而不仅仅是通过传统的 Web API 转发。 mongo_dart 是一个极其强大的、全功能、纯 Dart 实现的 MongoDB 驱动程序。它不依赖任何原生底层驱动(如 C 驱动),通过 Dart 的 Socket 机制直接实现 BSON 协议封装。这意味着你在鸿蒙设备上无需配置复杂的 NDK 动态库,即可拥有连接、查询、甚至是实时聚合分析 MongoDB 数据的能力。 一、网络直连架构模型

By Ne0inhk
Flutter for OpenHarmony:dart_ping 网络诊断的瑞士军刀(支持 ICMP Ping) 深度解析与鸿蒙适配指南

Flutter for OpenHarmony:dart_ping 网络诊断的瑞士军刀(支持 ICMP Ping) 深度解析与鸿蒙适配指南

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 在应用开发中,网络连通性检测是一个强需求。 * 用户的网络是 WiFi 还是 4G? * 虽然连着 WiFi,但是否真的能通公网(Ping www.baidu.com)? * 连接内网服务器的延迟是多少? 虽然 connectivity_plus 可以告诉我们网络类型(WiFi/Mobile),但它无法检测实际的连通性(比如 WiFi 连上了但没网)。这时,最直接的手段就是 Ping。 dart_ping 是一个跨平台的 Dart Ping 库。它并不重新实现 ICMP 协议(那需要 root 权限),而是巧妙地封装了各操作系统的原生 ping 命令,并解析其输出流。 对于

By Ne0inhk
Flutter 三方库 super_log 的鸿蒙化适配指南 - 实现极具视觉冲击力的彩色终端日志、支持动态过滤与全局异常捕获

Flutter 三方库 super_log 的鸿蒙化适配指南 - 实现极具视觉冲击力的彩色终端日志、支持动态过滤与全局异常捕获

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 super_log 的鸿蒙化适配指南 - 实现极具视觉冲击力的彩色终端日志、支持动态过滤与全局异常捕获 前言 在进行 Flutter for OpenHarmony 的日常开发调试时,面对控制台里密密麻麻、死板单调的白色日志,开发者很容易在大海捞针般的排错过程中产生疲劳。super_log 是一个专注于日志可视化体验的增强库。它通过丰富的配色方案和清晰的结构化打印,让鸿蒙控制台里的每条日志都具备“辨识度”。本文将介绍如何在鸿蒙端利用 super_log 让你的代码“自白”得更加生动。 一、原理解析 / 概念介绍 1.1 基础原理 super_log 基于终端的 ANSI 颜色转义序列。它通过解析日志级别,并在输出字符串中自动嵌入特定的颜色代码。同时,它还内置了美观的边框修饰符(Box

By Ne0inhk
Flutter for OpenHarmony:injector 轻量级依赖注入库(比 GetIt 更简单的选择) 深度解析与鸿蒙适配指南

Flutter for OpenHarmony:injector 轻量级依赖注入库(比 GetIt 更简单的选择) 深度解析与鸿蒙适配指南

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 依赖注入(Dependency Injection, DI)是解耦架构的核心。 在 Flutter 社区,get_it 是当之无愧的霸主,但有时候我们想要一个更简单、没有 Service Locator 模式那种“全局单例”味道的库,或者需要一个支持模块化注入的方案。 injector 是一个非常轻量的 DI 库。它不使用代码生成,提供基于构建器(Builder)的依赖注册机制。 对于 OpenHarmony 开发者,使用 DI 库可以将鸿蒙特定的实现(如 OhosPermissionService)与通用业务逻辑解耦,实现一套代码,多端运行。 一、核心原理 injector 的工作原理非常纯粹:它维护了一个 Map,

By Ne0inhk