算法热门:链表相交问题(LeetCode 160)
Posted 白龙码~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法热门:链表相交问题(LeetCode 160)相关的知识,希望对你有一定的参考价值。
Part I、何谓相交?
1、 文字解析
我们知道,链表可以分为单链表和双链表,前者有唯一的next指针指向下一个节点,而后者在此基础上新增了一个prev指针指向它的前一个节点,这是区别。但是共同点是,无论是next指针还是prev指针,它们指向的对象具有唯一性,这也是链表作为线性表最大的特点之一。
当我们知道链表的线性特性后,我们可以再来想:一个指针指向的节点确实具有唯一性,但是指向这个节点的指针并不具有唯一性。换句话说,可以同时有一个、两个甚至更多的指针同时指向一个节点(不过本篇文章我们只讨论一个,其余可以类推)。当出现这种情况时,我们可以说,这写指针所在的链表是相交的,交点就是这个唯一指向的节点。
2、图形解析
看完链表相交的文字解析,如果还有点懵懵的,不妨看看下面的图形示意:
可以看到,相交链表的图中,上下两个链表的第二个节点同时都指向同一个三号节点,因此说它们是相交的。
Part II、 进阶!
我们刚刚看了两链表在相交前节点数相等的情况,但事实上两链表长度是未知的,相交节点前的总结点数也是未知的。
方法一
如果节点长度相等,那么我们可以采取两链表同时从头到尾遍历的方式,当两个遍历指针相等且不为NULL时,代表相交节点找到了。
如果不相等,那么我们可以就需要一个m*n的嵌套循环遍历两个链表。什么意思?直接来看代码:
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
//方法一、O(m*n)的遍历
struct ListNode* cur1 = headA, *cur2 = headB;
while(cur1)
{
cur2 = headB;
while(cur2)
{
if(cur1 == cur2 && cur1)
{
return cur1;
}
cur2 = cur2->next;
}
cur1 = cur1->next;
}
return NULL;
}
外循环由cur1控制,内循环由cur2控制。cur1每走一步,cur2就需要从头到尾遍历一次链表,在遍历的过程中寻找非空的共同结点。
这种方法非常简单易懂且好想,但唯一的问题就是:时间复杂度为O(m*n),消耗较大,有没有什么效率更高的解法?
方法二
我们在前面的讨论中强调了的某一点非常重要:两个链表的长度。
为什么不能采取两链表同时从头到尾遍历的方式?因为它们的长度不同,为了走到相交的节点需要移动的次数不同。
那么,突破点就来了:只要让这两个链表在相交节点前的节点数相同就行了!
为什么这么说?
还是因为链表的线性特性——
如果两个链表相交了,那么相交节点后的部分是完全相同的,唯一不同的就是相交节点前的那些,因此可以断定:两个链表的长度差存在于相交节点前。
于是我们可以采取一种方法,就是:给两个链表中较短的那一个头插一些结点使其和长链表的长度相同,不过这也带来了O(N)的内存消耗。
所以我们不妨换一个思路:
让长的链表先遍历n个结点,其中n就是两个链表的长度差,然后再让两个链表同时遍历,不就可以达到目的了吗?
此时两个遍历的指针就是站在同一起跑线了,因为它们距离相交节点的距离是相同的。
代码实现一下:
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
//方法二、求出两链表的长度差x,让长的链表先走x,然后两链表再一起走,找出相同的节点
struct ListNode* cur1 = headA, *cur2 = headB;
int len1 = 0, len2 = 0;
while(cur1)
{
cur1 = cur1->next;
len1++;
}//求链表A的长度
while(cur2)
{
cur2 = cur2->next;
len2++;
}//求链表B的长度
struct ListNode* longList = headA, *shortList = headB;
if(len2 > len1)
{
longList = headB;
shortList = headA;
}//找出长的那个链表
int n = abs(len1-len2);//求出长度差
while(n--)
{
longList = longList->next;//让长的链表先走n个结点
}
while(longList && shortList)//遍历,找到相同的节点
{
if(longList == shortList)
return longList;
longList = longList->next;
shortList = shortList->next;
}
return NULL;
}
Part III、总结
一个链表相交的问题可以有多种思路,各有特色也各有优点,不过这里还是比较看好最后实现的这种,以O(n)的时间复杂度和O(1)的空间复杂度很好地解决了相交的问题!
如果对链表相交还有其他见解,欢迎评论区指教哦!
欢迎关注博主,定期分享各种题解!
以上是关于算法热门:链表相交问题(LeetCode 160)的主要内容,如果未能解决你的问题,请参考以下文章