链接
https://leetcode.cn/problems/3u1WK4/
题目
给定两个单链表的头节点 headA 和 headB ,请找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
图示两个链表在节点 c1 开始相交:题目数据保证整个链式结构中不存在环。
注意,函数返回结果后,链表必须保持其原始结构 。
示例:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at ‘8’
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
思路
- 两层遍历。将headA中的每个元素都与headB进行一次遍历,如果两个节点指针相等(即指向同一个节点),则该节点就是公共节点的起始点,进行返回。如果遍历结束,没有找到起始点,则返回
NULL
。该方法思路简单,但是耗时大。 - 哈希表。遍历一遍headA,将节点存入哈希表中。再对headB进行一次遍历,对每个元素在哈希表中进行查询,如果查到有该节点,则返回。遍历结束没有找到,则返回
NULL
。该方法思路简单,耗时相较于第一种少。 - 双指针。设置两个指针
pA
和pB
,分别等于headA
和headB
。
如果两个链表长度相等,那么两个指针最后会同时指向一个公共节点或者同时指向尾节点后的空节点。
如果两个链表长度不同。pA
遍历完链表,pB
遍历完链表,不会同时达到链尾。pA
遍历结束后移向headB
表头,pB
遍历结束后移向headA
表头。当两个指针都指向公共子链表的起始点,或者指向链尾后的空节点时,返回。可以想象成两个人以相同的速度在不同长度的赛道上跑步,允许到终点后换赛道,但不允许中途换,不允许暂停等待,不会有任何外界干扰因素,要求两个人最终相遇或者同时跑到终点(任一赛道的终点)。注:此处的终点是链尾后的NULL。
- 链表相交,最终相遇
1)两个链表相交。A长度m,B长度n,相交前长b,相交部分长c,A比B长k。pA
在A,pB
在B。
2)pA
和pB
同时开始跑,因为B赛道短,所以当pB
到达终点时,pA
还没到。此时pB
和pA
的已经跑了b+c
。pB
换赛道到A赛道。如下图:
3)当pA
跑到终点时,pA
更换到赛道B。
4)再跑距离b后,pA
和pB
相遇,此时返回。此点就是公共子链表的起始点。两个人跑了相同的距离:c+k+2*b
- 链表不相交,同时跑到终点
1)A赛道长a+b,B赛道长a
2)当pB
到B赛道的终点时,pA
没有到终点。pB
更换为A赛道。
3)当pA
到A赛道的终点时,pB
没有到终点。pA
更换为B赛道。
4)当pA
到达B赛道的终点时,pB
到底A赛道的终点。返回链尾后的NULL。
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
//第一种,两层遍历,一一对比
if(headA==NULL||headB==NULL)
return NULL;
ListNode *hA,*hB;
hA=headA;
hB=headB;
while(hA!=NULL){
while(hB!=NULL){
if(hA==hB)
return hA;
else
hB=hB->next;
}
hA=hA->next;
hB=headB;
}
return NULL;
//第二种,哈希表
if(headA==NULL||headB==NULL)
return NULL;
ListNode *tmp;
unordered_set<ListNode *> ans;
tmp=headA;
while(tmp!=NULL){
ans.insert(tmp);
tmp=tmp->next;
}
tmp=headB;
while(tmp!=NULL){
if(ans.count(tmp))
return tmp;
tmp=tmp->next;
}
return NULL;
//第三种,双指针
if(headA==NULL||headB==NULL)
return NULL;
ListNode *pA,*pB;
pA=headA;
pB=headB;
while(pA!=pB){
//此处指针为空时,相当于跑到了赛道的终点
pA=pA==NULL?headB:pA->next;
pB=pB==NULL?headA:pB->next;
}
return pA;
}
};