链表的公共节点

该博客讨论了如何在两个链表中找到第一个公共节点。首先检查空指针,然后判断链表是否有环。若无环,长链表先走长度差,再同步比较节点。若链表有环,需要考虑不同环情况下的交点问题。文章包含了求解此问题的相关代码和思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

输入两个链表,找出它们的第一个公共结点

这题一般就是比较两个链表的长度,更长的链表先走差值的步数,走完差值,开始两个链表同时走,同时比较是否指向同一个地址。两个链表就像Y型(图片来自kongmin_123):

代码如下:

def FindFirstCommonNode(self, pHead1, pHead2):
        # write code here
        if pHead1==None or pHead2==None:
            return None
        list1 = pHead1
        list2 = pHead2 
        while(list1!=list2):
            list1 = pHead2 if list1 is None else list1.next
            list2 = pHead1 if list2 is None else list2.next
        return list1

但是在查找这题的解法的时候,看见一个大佬整理的这个题目,觉得受益匪浅,在此附上链接与思路(两链表求公共节点-Felix):

首先需要考虑空指针输入,有一个输入为NULL,就不会有交点。

寻找两链表的第一个交点,简便的做法是求出两链表长度差diff后,让长的链表先走diff步,然后依次比较两链表节点,若相同则返回。

但这一个思路的前提是:两个链表都不含环。

因此,在考虑完空指针后,需要检验两个链表是否含有环。

(1) 若一个有环一个无环,则肯定没有交点。

(2) 若都无环,可以用上面的思路求出第一个交点;如果只要求返回bool,则比较一下两链表的尾节点是否相等即可。

(3) 两链表都含有环的情况下,如果只需要返回bool值,我们就检验其中一个链表的环入口是否在另一个链表的环上,在环上就返回true,表明相交,不在环上返回false。

如果要返回第一个交点呢?这时候我们可以分情况考虑:如果两个链表都是“勺型”,所谓勺型,就是指不是纯的环链表。那这两个勺型链表如果有交点,环部分肯定是已经百分百重叠了,第一个交点只能出现在“勺柄”上,既然是勺柄,自然就无环啦,因此,上面那个求两个无环链表的第一个交点的方法有可以拿来用了~

如果两个链表都有环,而且至少有一个是纯环链表,那么如果有交点,这个纯环链表必然所有节点都和另一个链表的环部分重合。此时,我们把那个纯环链表的输入节点(假设是head1)看作第一个交点,因此,只需要验证一下head1是否在另一个链表的环上即可。在的话就返回head1,不在就返回NULL。

 

因此这道题目其实并不简单,它包含“判断链表是否含有环”,“求环入口节点”,“求两条无环链表的第一个交点” 三个子问题。

这里给出引申问题,也就是求第一个交点的题目的代码,辅助函数traverse 的功能包含判断是否有环,返回环入口节点(无环则返回NULL),以及求头结点距离环入口节点(有环情况)或者尾节点(无环情况)的长度,这个长度被存在len变量里。

在判断是否有环的过程中,需要注意单节点环链表的情况。

 

### 找到两个链表的第一个公共节点 要找到两个单链表的第一个公共节点,可以采用一种高效的方法来解决这个问题。具体来说,可以通过比较两条链表的长度差异并调整起始位置的方式完成。 以下是具体的解决方案: #### 方法描述 1. **获取链表长度** 首先分别遍历两个链表 `L1` 和 `L2` 来获得其各自的长度 `len1` 和 `len2`[^3]。 2. **计算长度差值** 计算两者之间的长度差值 `dis = |len1 - len2|`。这一步是为了让较长的那个链表先行移动一定的步数,从而使得后续两者的剩余部分具有相同的长度[^4]。 3. **同步前进直到相遇** 调整之后,使两个指针同时向前移动,每次各前进一步。一旦发现当前所指向的内容相同,则找到了首个共同拥有的节点;如果到达结尾仍未遇到一致情况,则表明不存在任何交叉点[^5]。 下面是基于上述逻辑编写的C++代码实现: ```cpp struct ListNode { int val; struct ListNode *next; }; ListNode* findFirstCommonNode(ListNode* headA, ListNode* headB){ if(!headA || !headB) return nullptr; // Step 1: Calculate lengths of both lists. int lengthA = 0, lengthB = 0; ListNode* tempA = headA; ListNode* tempB = headB; while(tempA != NULL){ ++lengthA; tempA = tempA->next; } while(tempB != NULL){ ++lengthB; tempB = tempB->next; } // Reset pointers to start nodes after calculating their respective lengths. tempA = headA; tempB = headB; // Step 2: Move the pointer on longer list forward by difference in lengths. if(lengthA > lengthB){ for(int i=0;i<lengthA-lengthB;++i){ tempA = tempA->next; } }else{ for(int j=0;j<lengthB-lengthA;++j){ tempB = tempB->next; } } // Step 3: Traverse together until they meet or reach end. while(tempA && tempB){ if(tempA == tempB){ return tempA; // Found first common node. } tempA = tempA->next; tempB = tempB->next; } return nullptr; // No intersection found. } ``` 这段程序实现了寻找两个链表第一个公共节点的功能,并且时间复杂度为O(m+n),其中m,n分别是两个输入列表的大小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值