160. 相交链表 - 题解与详细分析

160. 相交链表 - 题解与详细分析

题目描述

给你两个单链表的头节点 headA 和 headB,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null

图示两个链表在节点 c1 开始相交:

text

A: a1 → a2 ↘ c1 → c2 → c3 ↗ B: b1 → b2 → b3

注意:

  • 题目数据保证整个链式结构中不存在环
  • 函数返回结果后,链表必须保持其原始结构

解题思路

这道题要求找到两个链表的相交节点。由于链表可能长度不同,但相交后的部分长度相同,我们可以通过以下方法解决:

核心思想

  1. 计算链表长度:分别遍历两个链表,得到它们的长度
  2. 对齐起点:让长链表先移动长度差值的步数,使两个链表的剩余长度相等
  3. 同时遍历:两个指针同时移动,比较节点是否相同

为什么这样有效?

  • 如果两个链表相交,那么从相交点到链表末尾的长度是相同的
  • 通过让长链表先走差值步,两个指针会同时到达相交点(如果存在)

代码实现

c

/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) { struct ListNode *cur1 = headA; struct ListNode *cur2 = headB; int a = 0; int b = 0; // 计算链表A的长度 while(cur1) { a++; cur1 = cur1->next; } // 计算链表B的长度 while(cur2) { b++; cur2 = cur2->next; } // 重置指针到链表头部 cur1 = headA; cur2 = headB; int c = 0; // 让长链表先移动长度差值的步数 if(a > b) { c = a - b; while(c--) { cur1 = cur1->next; } } else { c = b - a; while(c--) { cur2 = cur2->next; } } // 同时遍历两个链表,寻找相交节点 while(cur1) { if(cur1 == cur2) { return cur1; } cur1 = cur1->next; cur2 = cur2->next; } return NULL; }

代码详解

第一部分:计算链表长度

c

struct ListNode *cur1 = headA; struct ListNode *cur2 = headB; int a = 0; int b = 0; // 计算链表A的长度 while(cur1) { a++; cur1 = cur1->next; } // 计算链表B的长度 while(cur2) { b++; cur2 = cur2->next; }

  • 使用两个指针分别遍历两个链表
  • 计数器 a 和 b 分别记录链表A和链表B的长度

第二部分:对齐起点

c

cur1 = headA; cur2 = headB; int c = 0; if(a > b) { c = a - b; while(c--) { cur1 = cur1->next; } } else { c = b - a; while(c--) { cur2 = cur2->next; } }

  • 重置指针到链表头部
  • 计算长度差值 c
  • 让长链表的指针先移动 c 步,使两个指针后的剩余长度相等

第三部分:寻找相交节点

c

while(cur1) { if(cur1 == cur2) { return cur1; } cur1 = cur1->next; cur2 = cur2->next; } return NULL;

  • 两个指针同时移动
  • 比较节点地址是否相同(注意:是比较节点本身,不是节点值)
  • 找到相同节点则返回,否则返回 NULL

执行过程可视化

以题目示例为例:

text

链表A: a1 → a2 → c1 → c2 → c3 链表B: b1 → b2 → b3 → c1 → c2 → c3

执行步骤:

  1. 计算长度:
    • 链表A长度:5
    • 链表B长度:6
  2. 对齐起点:
    • 长度差:1
    • 链表B指针先移动1步:b2 → b3 → c1 → c2 → c3
  3. 同时遍历:
    • A: a1 → a2 → c1 → c2 → c3
    • B: b2 → b3 → c1 → c2 → c3
    • 在节点c1处相遇,返回c1

优化方案:双指针法

还有一种更巧妙的方法,不需要计算链表长度:

c

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) { if (headA == NULL || headB == NULL) return NULL; struct ListNode *pA = headA; struct ListNode *pB = headB; while (pA != pB) { pA = pA == NULL ? headB : pA->next; pB = pB == NULL ? headA : pB->next; } return pA; }

原理:

  • 两个指针分别遍历两个链表
  • 当指针到达链表末尾时,切换到另一个链表的头部
  • 如果两个链表相交,指针会在相交点相遇
  • 如果不相交,指针会同时到达NULL

复杂度分析

长度差法

  • 时间复杂度:O(m+n),其中m和n分别是两个链表的长度
  • 空间复杂度:O(1),只使用常数级别的额外空间

双指针法

  • 时间复杂度:O(m+n)
  • 空间复杂度:O(1)

关键点总结

  1. 比较节点地址:注意是比较节点本身(指针地址),不是节点值
  2. 链表无环:题目保证链表无环,简化了问题
  3. 保持原始结构:算法不应该修改链表结构
  4. 边界情况:处理空链表的情况

测试用例考虑

  1. 不相交的链表:返回NULL
  2. 完全相同的链表:返回头节点
  3. 一个链表是另一个的子集:返回较长链表的头部
  4. 在中间节点相交:返回相交节点
  5. 空链表:返回NULL

应用场景

这种链表相交问题在实际开发中有多种应用:

  1. 内存管理:检测两个数据结构是否共享内存区域
  2. 图算法:在树或图中寻找公共节点
  3. 版本控制系统:寻找代码分支的合并点
  4. 数据库查询:优化连接查询的执行计划

总结

寻找相交链表节点是一个经典的链表问题,掌握两种解法都很重要:

  1. 长度差法:思路直观,容易理解和实现
  2. 双指针法:代码简洁,不需要计算长度

关键技巧:

  • 利用相交后部分长度相同的特性
  • 通过对齐起点来简化比较过程
  • 注意指针操作和边界条件处理

这道题考察了对链表结构的理解和双指针技巧的应用,是面试中常见的问题之一。

Read more

猫头虎AI开源项目推荐:国产开源AI工具爱派(AiPy)|支持本地部署、Python Use自动化操作本地文件的AI办公神器

猫头虎AI开源项目推荐:国产开源AI工具爱派(AiPy)|支持本地部署、Python Use自动化操作本地文件的AI办公神器

猫头虎推荐:国产开源AI工具 爱派(AiPy)|支持本地部署、自动化操作本地文件的AI办公神器 随着AI大模型的迅猛发展,诸如Manus、OpenManus等产品的出现,一款安装即免费使用的AI办公助手成为当下的刚需,各行业正经历着前所未有的数字化转型。尤其对于数据工程师、数据分析师以及日常办公用户而言,如何更高效、更便捷地利用AI工具处理繁琐重复的任务,已成为迫切需要解决的问题。 本文将全面介绍一款领先的国产开源AI工具——爱派(AiPy),它不仅能帮助用户实现数据自动化处理,还能一键赋能AI控制本地文件处理,极大提升工作效率。 背景 作为数据工程师或分析师,你是否经常面对以下困扰? * 频繁处理各种格式的数据文件,包括 CSV、Excel、JSON、HTML、SQLite、Parquet 等; * 数据清洗、转换、聚合、排序、过滤、分析及可视化等工作反复重复,费时费力。 传统的数据处理流程通常十分繁琐: 1. 打开Python环境,输入如import pandas as pd等大量基础代码; 2. 在处理过程中产生许多临时文件;

By Ne0inhk
2026年1月远程工具横评:UU远程以全能六边形战士之姿,重塑行业性能标杆

2026年1月远程工具横评:UU远程以全能六边形战士之姿,重塑行业性能标杆

目录 写在前面:一场关于“效率”的军备竞赛 一、 核心突破:详解UU远程2026年1月重磅升级,如何解决远程协助世纪难题? 1.1 自定义验证码:把“报号码”从技术活变成家常便饭 1.2 客户端安全锁:远程协助时的“定海神针” 1.3 免登录远程协助:打破第一道门槛,实现真正“零门槛” 1.4 UU远程运维版定向开放:命令行批量管控,专为专业场景打造的效率引擎 二、 硬核横评:六大远程软件谁是2026年1月的性能之王? 2.1 性能之王:画质与延迟的终极较量 2.2 功能六边形战士:谁才是真正的全能王? 2.3 价格与限制:免费还是套路? 三、 综合评分与总结:2026年1月,你的最佳选择是谁?

By Ne0inhk
【Python 量化入门】AKshare 保姆级使用教程:零成本获取股票 / 基金 / 期货全市场金融数据

【Python 量化入门】AKshare 保姆级使用教程:零成本获取股票 / 基金 / 期货全市场金融数据

做量化交易、财经数据分析、投资复盘的开发者和投资者,经常会遇到核心痛点:付费金融数据接口成本高、免费 API 注册流程繁琐、多市场数据分散难以整合。告别 QMT 回测烦恼!手把手教你搭建 MiniQMT+Backtrader 量化回测框架 本文就给大家详细讲解 Python 量化圈的开源神器AKshare,从安装到核心功能实战全覆盖,代码可直接复制运行,零基础也能一键获取全市场金融行情数据。 一、AKshare 是什么? AKshare 是一款基于 Python 开发的开源金融数据接口库,专为个人投资者、量化爱好者、财经数据分析人员打造,是目前国内生态最完善、维护最活跃的免费金融数据工具之一。 它支持股票、期货、基金、外汇、债券、指数、加密货币等多种主流金融市场的数据获取,核心优势如下: * 免费开源:完全开源免费,无隐藏收费,个人非商用零成本使用,无需开通付费会员 * 数据覆盖全面:A 股、

By Ne0inhk
python101-高校学生宿舍报修系统vue3

python101-高校学生宿舍报修系统vue3

目录 * 系统概述 * 核心功能模块 * 技术实现要点 * 扩展性与优化方向 * 开发技术路线 * 相关技术介绍 * 核心代码参考示例 * 结论 * 源码lw获取/同行可拿货,招校园代理 :文章底部获取博主联系方式! 系统概述 Python101-高校学生宿舍报修系统基于Vue3前端框架开发,专为高校宿舍管理场景设计,实现学生在线提交报修请求、管理员处理工单、状态跟踪等功能。系统采用前后端分离架构,后端通常搭配Python(如Django或Flask)提供API支持。 核心功能模块 学生端功能 * 报修申请:填写故障类型、位置、描述并上传图片。 * 工单查询:实时查看报修进度(待处理/处理中/已完成)。 * 评价反馈:对已完成的维修服务进行评分或留言。 管理员端功能 * 工单分配:将报修任务指派给维修人员。 * 进度更新:修改工单状态并通知学生。 * 数据统计:分析故障高频类型及维修效率。 技术实现要点 * 前端技术栈:Vue3 + TypeScript + Element Plus/Pinia(

By Ne0inhk