编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输出解释:相交节点的值为2.
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
解释:两链表不相交所以输出null。
1.普通做法
因为两个链表只要有一个节点相等,之后就都相同,如上几张图所示。所以普通做法的思路就是想让两链表相交节点前不等长的地方右对齐,用两个指针从等长的地方开始遍历,若存在相同的点则返回那个点,否则平行。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *longlist,*shortlist;
ListNode *p = headA,*q = headB;
int dist=0;
int Len1 = 0;
int Len2 = 0;
while(p){ //两个while用于记录A,B的链表表长
++Len1;
p = p -> next;
}
while(q){
++Len2;
q = q -> next;
}
if(Len1 > Len2) //这个if用于将长短表的差值赋给dist
{
longlist = headA->next;
shortlist = headB->next;
dist = Len1 - Len2;
}else
{
longlist = headB->next;
shortlist = headA->next;
dist = Len2 - Len1;
}
while(dist && longlist != NULL) //执行循环直到dist等于0,意思就是让长表的指针指向对应短表表头的位置,即对齐
{
longlist = longlist->next;
}
while(longlist != NULL) //这里写shortlist也可以,因为已经对齐了
{
if(longlist->val == shortlist->val) //如果存在相同的节点,说明有交点,返回这个节点
{
return longlist;
}else
{
longlist = longlist->next;
shortlist = shortlist->next;
}
}
return NULL; //结束了while循环,说明没有相同的节点,也就是说两链表平行,所以return NULL
}
};
2.巧妙做法
先上图
比如一个相交链表A前面有4个节点,相交及相交后有3个节点;B相交前有2个节点,相交后有3个节点。B遍历完一共遍历了5个节点,再从A一直遍历到相交节点一共便利了5+5=10个,而A遍历完一共遍历了7个节点,再从B遍历到相交节点,一共遍历了7+3=1个。因为路程是一样的,所以最后肯定会遍历到相交节点。
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; //如果pA不为空则指向pA下一个,为空则从headB开始遍历,下同
pB = pB == null ? headA : pB.next;
}
return pA;
}