一句话总结:
判断链表交叉就像找两个人走的路有没有汇合点——要么用「脚印记录法」(哈希表),要么用「对齐起点法」(双指针)!
一、链表交叉示例
链表A:1 → 3 → 5
↘
7 → 9 → null
↗
链表B:2 → 4
关键点: 交叉后的节点共用(如节点7、9)
二、哈希表法(脚印记录法)
原理: 把链表A所有节点存进哈希表,遍历链表B时检查是否有重复节点
Kotlin 代码:
data class ListNode(val value: Int, var next: ListNode? = null)
// 哈希表法检测交叉点
fun getIntersectionNodeHash(headA: ListNode?, headB: ListNode?): ListNode? {
val visited = hashSetOf<ListNode>() // 存储链表A的所有节点
var currentA = headA
// 记录链表A的节点
while (currentA != null) {
visited.add(currentA)
currentA = currentA.next
}
// 检查链表B是否有重复节点
var currentB = headB
while (currentB != null) {
if (visited.contains(currentB)) return currentB
currentB = currentB.next
}
return null
}
时间复杂度: O(m + n)
空间复杂度: O(m)(m为链表A长度)
三、双指针法(对齐起点法)
原理: 计算两链表长度差,让长链表先走差值步,然后两指针同步前进
Kotlin 代码:
fun getIntersectionNode(headA: ListNode?, headB: ListNode?): ListNode? {
// 获取链表长度
fun getLength(head: ListNode?): Int {
var len = 0
var curr = head
while (curr != null) {
len++
curr = curr.next
}
return len
}
val lenA = getLength(headA)
val lenB = getLength(headB)
var currA = headA
var currB = headB
// 长链表先走差值步
if (lenA > lenB) {
repeat(lenA - lenB) { currA = currA?.next }
} else {
repeat(lenB - lenA) { currB = currB?.next }
}
// 同步前进找交叉点
while (currA != null && currB != null) {
if (currA == currB) return currA
currA = currA.next
currB = currB.next
}
return null
}
时间复杂度: O(m + n)
空间复杂度: O(1)
四、测试用例
fun main() {
// 构造交叉链表
val commonNode = ListNode(7).apply {
next = ListNode(9)
}
val headA = ListNode(1).apply {
next = ListNode(3).apply {
next = ListNode(5).apply {
next = commonNode
}
}
}
val headB = ListNode(2).apply {
next = ListNode(4).apply {
next = commonNode
}
}
// 测试哈希表法
println(getIntersectionNodeHash(headA, headB)?.value) // 输出7
// 测试双指针法
println(getIntersectionNode(headA, headB)?.value) // 输出7
// 测试无交叉情况
val headC = ListNode(10)
println(getIntersectionNode(headA, headC)) // 输出null
// 测试其中一个链表为空
println(getIntersectionNode(null, headB)) // 输出null
}
五、关键点解析
- 节点相等判断:比较节点引用(
===),不是比较值 - 处理空链表:任一链表为空直接返回null
- 交叉点可能在头节点:如链表B直接指向链表A的头节点
口诀:
链表交叉不用愁,
哈希双指针任你投。
对齐起点或浪漫走,
抓住共同节点就收工!