小白算法积累——单链表8#两个单链表的公共节点

题目:给定两个单链表,编写算法找出两个链表的公共结点

关键字:两个链表+查找公共节点

思路
两个单链表有公共节点,意味着:两个链表从某一结点开始,它们的next都指向同一个结点。由于每个单链表结点只有一个next域,因此从第一个公共结点开始,之后它们所有的结点都是重合的,不可能再出现分叉。
所以,两个有公共结点而部分重合的单链表,拓扑形状看起来像Y,而不可能像X

“低级思路”:在第一个链表上顺序遍历每个结点,每遍历一个结点,在第二个链表上顺序遍历所有结点,若找到两个相同的结点,则找到了它们的公共结点。显然,改算法的时间复杂度为O(len1*len2)

“高级思路”:
先把问题简化(从结果倒退寻找线索):
首先,最基本的底层问题,
Q:如何判断两个单向链表有没有公共结点?
A:若某点为两个链表的公共结点,那么,该公共结点之后所有的结点都是重合的,所有它们的最后一个结点必然是重合的。

因此,判断两个单链表是否有公共结点的核心,就是判断两个链表的尾结点是否一样。
如果尾结点一样,则它们有公共节点。
否则,它们一定没有公共结点。

然鹅,在上面的思路中,顺序表遍历两个链表到尾结点时,并不能保证在两个链表上同时到达尾结点。
这是因为两个链表长度不一定一样。
Q:如何解决两个链表同时扫描到首个公共结点呢?
A:假设一个链表比另一个长k个结点,我们先在长的链表上遍历k个结点,之后再同步遍历。
此时我们就能保证同时到达最后一个结点。
由于两个链表从第一个公共结点开始到链表的尾结点,这一部分是重合的,
因此它们肯定也是同时到达第一公共结点的。
于是在遍历中,第一个相同的结点就是第一个公共的结点。

具体步骤:`
1.分别遍历两个链表得到它们的长度,并求出两个长度之差。
需要变量:L1,L2 ,
两个表各自的长度; len1,len2
各自的指针LinkList longlist,shortlist

2.在长的链表上先遍历长度之差个结点之后,再同步遍历两个链表,
直到找到相同的结点,或者一直到链表结束
需要变量:长度之差:dist
此时时间复杂度为O(len1+len2),高效了很多。

LinkList Search_1st_Common(LinkList L1,LinkList L2){//本算法实现在线性的时间内找到两个单链表的第一个公共结点
     int len1=Length(L1),len2=Length(L2);//计算两个链表的表长
     LinkList longList,shortList;//分别指向表长较长和较短的链表
     if(len1>len2){//当L1表长较长
     longList=L1->next;shortList=L2->next;
     dist=len1-len2;//表长之差
    }
    else
      longList=L2->next;shortList=L1->next;//L2表长较长
      dist=len2-len1;//表长之差
    }
    while(dist--)//较长的链表先遍历到第dist个结点
        longList=longList->next;
    while(longList!=NULL){//开始同步遍历,寻找共同结点
       if(longList==shortList)//找到第一个公共结点
         return longList;
       else{//继续同步寻找
           longList=longList->next;
           shortList=shortList->next;
         }
       }
       return NULL;
     }
      
}
     


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值