1. 链表的基本概念(面向初学者)
什么是链表?
链表是一种数据结构,由多个节点(Node)组成。
每个节点包含 两个部分:
- 数据部分:存储实际的数据,比如
整数
、字符串
等。 - 指针部分:存储指向下一个节点的地址,告诉我们下一个节点在哪里。
在 Java 中,我们可以用一个 类(Class) 来定义链表的 节点(Node):
class ListNode {
int val; // 存储数据
ListNode next; // 指向下一个节点
ListNode(int val) {
this.val = val;
this.next = null; // 初始时,没有下一个节点
}
}
这样,每个 ListNode
对象代表链表中的一个 节点。
2. 题目分析:寻找两个链表的交点
题目描述
- 输入:给定两个链表
headA
和headB
。 - 输出:找到 第一个 相交的节点,如果没有交点,返回
null
。
示例链表结构:
链表A:a1 -> a2 -> c1 -> c2 -> c3
链表B:b1 -> b2 -> b3 -> c1 -> c2 -> c3
从 c1
开始,两个链表合并,形成交点。
3. 解题思路
核心思路
- 计算两个链表的长度(找到哪个链表更长)。
- 调整起点:让较长的链表先走几步,使得两个链表的起点对齐。
- 同步遍历:从相同的位置同时遍历,找到第一个相交的节点。
4. Java 代码实现
// 定义链表的节点结构
class ListNode {
int val; // 节点存储的数据
ListNode next; // 指向下一个节点的指针
ListNode(int val) {
this.val = val;
this.next = null; // 初始时,没有指向下一个节点
}
}
public class Solution {
// 计算链表长度的辅助方法
public int getLength(ListNode head) {
int length = 0;
while (head != null) {
length++; // 每遍历一个节点,长度加1
head = head.next; // 移动到下一个节点
}
return length;
}
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
// 计算两个链表的长度
int lenA = getLength(headA);
int lenB = getLength(headB);
// **让较长的链表先走几步**
while (lenA > lenB) {
headA = headA.next; // A比B长,就让A先走
lenA--; // A向前走一步,长度减1
}
while (lenB > lenA) {
headB = headB.next; // B比A长,就让B先走
lenB--; // B向前走一步,长度减1
}
// **同步遍历,寻找交点**
while (headA != null && headB != null) {
if (headA == headB) {
return headA; // 找到交点,返回该节点
}
headA = headA.next;
headB = headB.next;
}
return null; // 没有交点,返回 null
}
}
5. 详细代码解析(针对初学者)
第一部分:定义链表节点
class ListNode {
int val; // 存储数据
ListNode next; // 指向下一个节点
ListNode(int val) {
this.val = val;
this.next = null; // 初始时,没有指向下一个节点
}
}
ListNode
是一个链表节点的类。val
是节点存储的数据,例如3
、7
。next
是指向下一个节点的指针。
第二部分:计算链表长度
public int getLength(ListNode head) {
int length = 0;
while (head != null) {
length++; // 遍历链表,每遇到一个节点,长度加1
head = head.next; // 移动到下一个节点
}
return length;
}
这个方法的作用:
- 传入一个链表
head
,计算它的长度。 - 循环遍历,每访问一个节点,长度
+1
,直到null
(链表末尾)。 - 返回链表的总长度。
第三部分:调整较长链表的起点
while (lenA > lenB) {
headA = headA.next; // A比B长,A先走一步
lenA--; // 长度减少
}
while (lenB > lenA) {
headB = headB.next; // B比A长,B先走一步
lenB--;
}
为什么要调整?
- 让两个链表的起点对齐。
- 例如:
headA
长度 = 5headB
长度 = 3- 让
headA
先走 2 步,让它们对齐。
第四部分:同步遍历寻找交点
while (headA != null && headB != null) {
if (headA == headB) {
return headA; // 找到交点,返回节点
}
headA = headA.next;
headB = headB.next;
}
return null; // 没有交点,返回 null
遍历方式:
- 同时遍历两个链表。
- 如果
headA == headB
,说明找到了交点,直接返回。 - 如果遍历结束仍然没有相等的节点,返回
null
(说明两个链表不相交)。
6. 代码运行示例
构造链表:
public static void main(String[] args) {
ListNode a1 = new ListNode(1);
ListNode a2 = new ListNode(2);
ListNode c1 = new ListNode(3);
ListNode c2 = new ListNode(4);
ListNode c3 = new ListNode(5);
ListNode b1 = new ListNode(6);
ListNode b2 = new ListNode(7);
ListNode b3 = new ListNode(8);
a1.next = a2;
a2.next = c1;
c1.next = c2;
c2.next = c3;
b1.next = b2;
b2.next = b3;
b3.next = c1;
Solution solution = new Solution();
ListNode intersection = solution.getIntersectionNode(a1, b1);
if (intersection != null) {
System.out.println("相交节点的值是:" + intersection.val);
} else {
System.out.println("两个链表没有相交");
}
}
输出结果:
相交节点的值是:3
7. 总结
- 计算两个链表的长度。
- 调整较长的链表起点,让两个链表从相同位置开始遍历。
- 同步遍历寻找交点,找到就返回节点,没有交点就返回
null
。