LeetCode面试HOT100——160. 相交链表

相交链表双指针最优解

相交链表代码超详细解析(双指针最优解)

这段代码是力扣「相交链表」问题的 双指针最优解(时间复杂度O(n+m)、空间复杂度O(1)),核心思路是「让两个指针走相同的总路程,最终在相交节点相遇」。下面从「问题本质→代码逻辑→分步演示→关键细节」帮你彻底吃透。

一、先明确问题本质

1. 相交链表的定义

两个链表相交,指的是 节点引用相同(不是值相同),即从相交节点开始,后续所有节点都完全共用(结构上是"Y"形,不是"X"形)。

例:链表A:1→2→3→4→5,链表B:6→7→3→4→5,相交节点是3(两个链表的3是同一个节点,后续45也共用)。

2. 核心痛点

两个链表长度可能不同(设为n和m),直接遍历无法同步到达相交节点。

常规思路(如哈希表存节点)需要额外空间,而双指针法能做到「无额外空间」求解。

3. 算法核心思想(等效路程法)

让两个指针分别从链表A、B的头节点出发,按以下规则移动:

  • 指针h1遍历完链表A(走到null)后,立刻转向链表B的头节点继续遍历;

  • 指针h2遍历完链表B(走到null)后,立刻转向链表A的头节点继续遍历;

  • 最终,两个指针会走 相同的总路程(n+m)

    • 若两链表相交:两指针会在相交节点相遇(h1 == h2);

    • 若不相交:两指针会同时走到null(h1 == h2 == null)。

原理:总路程相同 + 速度相同(每次走1步),必然同时到达终点(或相交点)。

二、代码逐行拆解(带注释)

Java 复制代码

三、分步演示(两种场景)

为了直观理解,分「两链表相交」和「两链表不相交」两种情况演示。

场景1:两链表相交(A长度=5,B长度=4,相交节点为3)

链表A:1→2→3→4→5(节点:A1、A2、A3、A4、A5)

链表B:6→7→3→4→5(节点:B1、B2、A3、A4、A5)

总路程:5+4=9步,两指针各走9步后相遇。

步数 h1(从A出发) h2(从B出发) 备注
0 A1(1) B1(6) 初始状态
1 A2(2) B2(7) 均未到终点,继续走
2 A3(3) A3(3) 此时h1=h2,相遇!循环结束
关键:h1走了2步到A3,h2走了2步到A3(总路程都是2,因两链表在A3相交,后续路程相同,提前相遇)。

场景2:两链表不相交(A长度=3,B长度=2)

链表A:1→2→3→null

链表B:4→5→null

总路程:3+2=5步,两指针各走5步后同时到null。

步数 h1(从A出发) h2(从B出发) 备注
0 A1(1) B1(4) 初始状态
1 A2(2) B2(5) 均未到终点
2 A3(3) null(B遍历完) h2转向A的头(A1)
3 null(A遍历完) A1(1) h1转向B的头(B1)
4 B1(4) A2(2) 继续走
5 B2(5) A3(3) 继续走
6 null(B遍历完) null(A遍历完) h1=h2=null,循环结束
关键:两指针都走了6步(总路程3+2=5?实际因null也算一步,最终同时到null,返回null正确)。

四、关键细节与避坑点

1. 为什么循环条件是h1 != h2

  • 若相交:h1和h2会在相交节点相等,循环终止,返回该节点;

  • 若不相交:h1和h2会同时走到null(h1h2null),循环终止,返回null(符合题目要求)。

2. 为什么指针走到null后要转向另一个链表的头?

核心是「凑齐相同总路程」。假设A长度n,B长度m:

  • h1的路径:A的n个节点 + B的m个节点(总n+m);

  • h2的路径:B的m个节点 + A的n个节点(总m+n);

总路程相同,速度相同(每次1步),必然同时到达终点(或相交点)。

3. 会不会陷入死循环?

不会!因为两指针的总路程是固定的(n+m),最多走n+m步后,必然会同时走到null(h1==h2),循环一定会终止。

4. 边界情况是否覆盖?

  • 其中一个链表为空(headAnull):h1初始为null,h2遍历完B后转向A(null),最终h1h2==null,返回null(正确);

  • 两个链表长度相同且相交:两指针同步走,直接在相交节点相遇;

  • 两个链表长度相同且不相交:同时走到null,返回null。

5. 为什么比哈希表方法更优?

哈希表方法(存A的所有节点,再遍历B查找)的时间复杂度是O(n+m),但空间复杂度是O(n)(需要存A的节点);而双指针法空间复杂度是O(1)(仅用两个指针),是最优解法。

五、总结

这段代码的核心是「等效路程法」:

  1. 双指针分别从两个链表头出发,遍历完一个链表后立刻转向另一个链表;

  2. 总路程相同 → 必然同时到达终点(或相交点);

  3. 循环终止时,h1和h2要么是相交节点,要么都是null,直接返回即可。

记住一句话:"你走我的路,我走你的路,我们终将相遇(或一起到尽头)",就能轻松理解并默写这段代码!如果还是不理解,建议动手画一画指针移动的每一步,可视化后会瞬间清晰。

相关推荐
xuansec几秒前
PHP 反序列化漏洞学习笔记(CTF向总结)
笔记·学习·php
小比特_蓝光1 分钟前
算法篇1-----双指针
数据结构·算法
阿波罗尼亚3 分钟前
JDK17 新特性
java
独自破碎E3 分钟前
【面试真题拆解】Spring事务机制
java·spring·面试
程序员爱钓鱼4 分钟前
Go PDF处理利器: github.com/pdfcpu/pdfcpu 深度指南
后端·面试·go
我是咸鱼不闲呀5 分钟前
力扣Hot100系列21(Java)——[多维动态规划]总结(不同路径,最小路径和,最长回文子串,最长公共子序列, 编辑距离)
java·leetcode·动态规划
Luna-player7 分钟前
第3章 Spring Boot的Web应用支持,个人学习笔记
前端·spring boot·学习
lihao lihao8 分钟前
二分查找
java·数据结构·算法
Albert Edison8 分钟前
【C++11】可变参数模板
java·开发语言·c++
WolfGang00732111 分钟前
代码随想录算法训练营 Day15 | 二叉树 part05
数据结构·算法