问题描述:
给定两条链表的头结点headA, headB,判断这两条链表是否相交,如果相交找出相交开始的节点。
方法一
两个指针pA、pB分别遍历两条链表至尾节点(不是尾结点的下一个节点null)并统计节点数lenA、lenB,如果最后pA == pB,则说明链表相交,否则,不相交。
如果相交,让pA、pB分别从指向链表头部,根据lenA、lenB判断哪个链表更长,让更长链表的指针先走|lenA-lenB|
步,然后pA、pB同时走,直到pA == pB,则pA或pB即为相交节点。
伪码:
public ListNode GetIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null)
return null;
int lenA = 0, lenB = 0;
ListNode pA = headA, pB = headB;
// pA,pB分别遍历至尾结点并计数
for(; pA.next != null; pA = pA.next, lenA ++);
for(; pB.next != null; pB = pB.next, lenB ++);
if (pA != pB)
return null;
// pA指向更长链表的头结点,pB指向较短的
pA = headA;
pB = headB;
if (lenA < lenB) {
pA = headB;
pB = headA;
}
// 较长先走
for(int i = 0; i < Math.Abs(lenA - lenB); nodeA = nodeA.next, i++);
// 再同时走
for(;nodeA != nodeB;nodeA = nodeA.next, nodeB = nodeB.next);
return nodeA;
}
方法二
同样两个指针pA、pB同时走,如果pA == null,则让pA = headB(即指向B链表头结点),否则pA = pA.next,如果pB == null ,则让pB = headA(即指向A链表头结点), 否则pB = pB.next。循环终止条件是pA != pB。
- 如果两条链表不相交,则两个指针pA、pB同时走了
lenA + lenB
步后分别到达了B链、A链的末尾,都为null,循环结束。
- 如果两条链表相交,则两个指针同时走了相同步数
x + y + z
后,同时到达相交节点。
伪码:
public ListNode GetIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return null;
}
ListNode pa = headA, pb = headB;
while(pa != pb) {
pa = pa == null ? headB : pa.next;
pb = pb == null ? headA : pb.next;
}
return pa;
}
总结
方法二代码更简洁,方法一更容易想到和理解
例题
leetcode 160. 相交链表