【Leetcode】160-相交链表

题目简述

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。

示例 1:
输入:listA = [4,1,8,4,5], listB = [5,6,1,8,4,5]
输出:8

示例 2:
输入:listA = [1,9,1,2,4], listB = [3,2,4]
输出:2

思路分析:

这个问题的难点在于两个链表长度不一定相等,如果链表长度相等的话直接使用两个指针指向表头然后同步前进两两对比两表节点值,这样就方便找到链尾节点相同的相交节点了。因此我们需要先找到两链表中使得尾部长度对齐的同步起点,这是问题的关键。
那么如何找到这样的同步起点呢?
容易想到先找到两表长度之差d,再从更长的链表移动d个节点之后就是两表的同步起点了。
最简单的方法是分别遍历两个链表,记录节点个数以得到链表长度a和b,然后得到两表长度之差d,再分别遍历两个链表,其中需要在长链表中先移动d个节点,然后在同步起点处开始对两链表中的节点两两比较。这样我们总共遍历了3次才找到同步起点。
其实还有更偷懒的方法,一次遍历就可以找到同步起点。
我们使用双指针(假设为p、q),分别指向两个表头ListA、ListB,并在一次遍历中同时向后移动。请注意,如果两表不一样长(假设ListB长于ListA),总有一个指针会先遇到当前表的末尾节点(假设为p),此时将它转向指向另一链表的表头从头遍历同时另一指针仍然在更长的链表中继续遍历,两指针在本次迭代中继续向后移动直到更长的链表也遇到末尾节点。此时可知,原本指向更短链表ListA表头的p节点此时指向的就是在更长链表ListB中移动了节点数之差d的后一个节点,也就是我们要找的使得两表尾部长度相等的同步起点。由于此时指针q已经指向ListB的末尾,我们重新指派其指向ListA表头,则此时p和q指针都指向了ListA和ListB中的同步起点。
找到同步起点(仅说明两个链表从各自同步起点到链尾的节点个数相同)之后,需要找到交叉节点(交叉节点之后的每个节点值都相同)。
如何找到交叉节点?
由于此问题中相交链表相交的结点是公共的节点(而不是仅指同值节点),故判断条件可简单设为 while pA != pB,直到发现相同的Listnode即可返回。(而不用从第一个值相等的节点到链尾逐个比较 pA .val == pB.val)

代码示例

class Solution:    
	def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
	        pA, pB = headA, headB        
	        while pA != pB:            
	        	pA = pA.next if pA else headB
	        	pB = pB.next if pB else headA
	        return pA

算法复杂度

时间复杂度 O ( m + n ) O(m+n) O(m+n)
空间复杂度 O ( 1 ) O(1) O(1)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值