题目来源:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/description/
题目描述:
解法一:
先统计两根链表的长度,分别为lenA,lenB。然后两根链表都从头开始遍历,并且让长的链表先跑k步(k为两根链表长度之差)。
然后再同时向后跑,直到跑到相同结点为止。
代码如下:
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null)
return null;
ListNode ha = headA, hb = headB;
int lenA = 1, lenB = 1;
while (ha.next != null) {
ha = ha.next;
lenA++;
}
while (hb.next != null) {
hb = hb.next;
lenB++;
}
ha = headA;
hb = headB;
return getNode((lenA < lenB) ? hb : ha, (lenA < lenB) ? ha : hb, (lenA < lenB) ? lenB - lenA : lenA - lenB);
}
public ListNode getNode(ListNode l, ListNode s, int len) {
for (int i = 0; i < len; i++) {
l = l.next;
}
while (l != null) {
if (l == s)
break;
l = l.next;
s = s.next;
}
return l;
}
}
解法二(双指针法):
双指针解法顾名思义需要两个指针,假设指针 pA
和 pB
分别指向链表 A 和链表 B 的头结点,之后两个指针分别以步幅为 1 的速度向链表的尾部遍历,当指针 pA
遍历到链表 A 的尾节点时,将指针 pA
指向链表 B 的头部。同样地,当指针 pB
遍历到链表 B 的尾节点时,将指针 pB
指向链表 A 的头部。当两个指针相遇时,指针 pA
或者 pB
所指向的节点就是两个链表的相交节点。
为了说明双指针的求解思路,假设链表 A 和链表 B 的结构如下图所示,
其中,链表 A 包含 6 个节点,节点的值分别为 1、3、5、7、9 和 11;链表 B 包含 4 个节点,节点的值分别为 2、4、9 和 11,因此,两个链表的相交节点为 9。设链表 A 中不相交的部分(即蓝色部分的节点)长度为 L1 L1 ,链表 B 中不相交的部分(即黄色部分的节点)长度为 L2 L2 ,两个链表相交的部分(即红色部分的节点)长度为 L3 L3 。
如下图所示,当指针 pB
遍历到链表 B 的尾节点 11 时,指针 pA
遍历到链表 A 中节点 7 的位置,下一次遍历指针 pB
将处于链表 A 的节点 1 的位置。
同理,当指针 pA
遍历到链表 A 的尾节点 11 时,此时指针 pB
处于链表 A 中节点 3 的位置,下一次遍历指针 pA
将处于链表 B 的节点 2 位置。
再经过两次遍历后,指针 pA
将位于链表 B 中节点 4 的位置,而指针 pB
也将到达链表 A 的节点 4 的位置,下一次遍历两个指针将在节点 9(即相交节点)相遇。此时,两个指针走过的长度都为 L1+L2+L3 L1+L2+L3 。究其原因,可以将两个指针走过的“路程”看成 3 个部分,即蓝色部分、红色部分以及橙色部分,只是两个指针走过 3 个部分的顺序是不同的,指针 pA
先走蓝色部分而指针 pB
先走橙色部分,但是经过前 3 个部分后,两个指针走过的长度一定是相同的,因此在下一次遍历的时候两个指针一定会相遇。
代码如下:
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return null;
}
ListNode pA = headA;
ListNode pB = headB;
while (pA != pB) {
pA = pA == null ? headB : pA.next;
pB = pB == null ? headA : pB.next;
}
return pA;
}
}