题目
【输入两个链表,找出它们的第一个公共结点】
1、分析
-
使用暴力法是将一个链表(长为m)中的每个元素分别与另一个链表(长为n)中的元素进行比较,时间复杂度为 O ( m ∗ n ) O(m*n) O(m∗n)
-
进一步分析可知,两个链表有一个公共的节点,则从某一节点开始,它们的 p->next 相同(即指针指向同一个节点)。同时由于该链表为单向链表,所以从第一个公共节点开始,之后它们所有的节点都是重合的,一直到最后结束。如下图示例所示:
-
接下来有两种思路
- 借助辅助空间:由于公共节点最有可能在链表的尾部(也有极端情况是首节点就是公共节点,即两个链表完全相同),所以可以从尾节点开始进行遍历,逐渐向前,直至查出第一个公共节点。这种方法需要借助栈来分别将两个链表存入其中,因为栈先进后出,所以是首先比较尾节点。该方法由于借助了两个栈,因此空间复杂度为 O ( m + n ) O(m+n) O(m+n) ,其时间复杂度也是 O ( m + n ) O(m+n) O(m+n) 。
- 采用长链表先走的方法:首先分别遍历两个链表,得到两链表的长度。然后求出两个链表的长度差为 dis ,让比较长的链表先走 dis 步,然后再让两个链表同时走,并比较其是否为首个公共节点。两个链表会同时到尾节点。该方法不需要辅助空间,同时其时间复杂度也为 O ( m + n ) O(m+n) O(m+n),因此该方法为最佳方案
2、代码
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if(!headA || !headB) return nullptr;
int n1=0, n2=0;
ListNode *p1=headA, *p2=headB;
while(p1)
{
++n1;
p1=p1->next;
}
while(p2)
{
++n2;
p2=p2->next;
}
p1=headA, p2=headB;
while(n1!=n2)
{
if(n1>n2)
{
p1=p1->next;
--n1;
}
if(n1<n2)
{
p2=p2->next;
--n2;
}
}
while(p1)
{
if(p1==p2)
return p1;
p1=p1->next;
p2=p2->next;
}
return nullptr;
}
};