解法一:双指针
如果用两个指针 p1 和 p2 分别在两条链表上前进,我们可以让 p1 遍历完链表 A 之后开始遍历链表 B,让 p2 遍历完链表 B 之后开始遍历链表 A,这样相当于「逻辑上」两条链表接在了一起,那么就可以让 p1 和 p2同时进入公共部分,也就是同时到达相交节点
如果说两个链表没有相交点,这个逻辑可以覆盖这种情况的,相当于 c1 节点是空指针 null 嘛,还是可以正确返回 null。
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func getIntersectionNode(headA, headB *ListNode) *ListNode {
p1, p2 := headA, headB
for p1 != p2{
if p1 == nil{ // p1 如果走到 A 链表末尾,转到 B 链表
p1 = headB
}else {
p1 = p1.Next
}
if p2 == nil{ // p2 如果走到 B 链表末尾,转到 A 链表
p2 = headA
}else {
p2 = p2.Next
}
}
return p1
}
解法二:计算剩余距离
先计算两条链表的长度,然后让 p1 和 p2 距离链表尾部的距离相同,然后齐头并进
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func getIntersectionNode(headA, headB *ListNode) *ListNode {
p1, p2 := headA, headB
// 计算两个链表的长度
lenA, lenB := 0, 0
for p1 != nil{
p1 = p1.Next
lenA++
}
for p2 != nil{
p2 = p2.Next
lenB++
}
// 重置遍历起点指针的位置
p1, p2 = headA, headB
// 将两个起点调整为距离尾部相同的距离,即走到结尾的步长保持一致
if lenA > lenB{
// A链表更长,应该挪动p1
for i := 0; i<lenA-lenB; i++{
p1 = p1.Next
}
}else if lenB > lenA{
// B链表更长,应该挪动p2
for i:=0; i<lenB-lenA; i++{
p2 = p2.Next
}
}
// 如果lenA=lenB,则一开始p1和p2距离尾部距离一样
// 接下来p1和p2齐头并进,只需要不断判断是否遍历到了同个节点即可
for p1 != p2{ // 不相交都走到了末尾,都为nil也会命中循环退出条件
p1 = p1.Next
p2 = p2.Next
}
return p1
}