假设有两个单链表,它们在某个点相交并成为单个链表 .
两个列表的头部或起始指针都是已知的,但交叉节点是未知的 . 此外,列表中每个列表中的节点数量在它们相交之前是未知的,并且两个列表可能具有不同,即List1在到达交叉点之前可能有n个节点,而List2可能在到达交点之前有m个节点,其中m和n可能是
-
m = n,
-
m <n或
-
m> n
一种已知或简单的解决方案是将第一列表中的每个节点指针与第二列表中的每个其他节点指针进行比较,匹配节点指针将通过该指针引导我们到交叉节点 . 但是,在这种情况下,时间复杂度将是O(n2),这将是很高的 .
找到交叉节点的最有效方法是什么?
6 回答
这需要O(M N)时间和O(1)空间,其中M和N是链表的总长度 . 如果公共部分很长(即M,N >> m,n)可能效率低下
遍历两个链表以找到M和N.
回到头部,然后遍历| M - N |较长列表上的节点 .
现在进入锁定步骤并比较节点,直到找到常见节点 .
编辑:见http://richardhartersworld.com/cri/2008/linkedlist.html
如果可能,您可以添加“颜色”字段或类似于节点 . 迭代其中一个列表,随时为节点着色 . 然后迭代第二个列表 . 一旦到达已经着色的节点,就会找到交叉点 .
将两个列表的内容(或地址)转储到一个哈希表中 . 第一次碰撞是你的交集 .
检查每个列表的最后一个节点,如果有一个交叉点,它们的最后一个节点将是相同的 .
这是我在深夜编码时发现的疯狂解决方案,它比接受的答案慢2倍但使用了一个很好的算术黑客:
我们将列表拆分为三个部分:
a
这是第一个列表的一部分,直到公共部分开始,b
这是第二个列表的一部分,直到公共部分和c
这是两个列表的共同部分 . 我们计算列表大小然后反向列表b
,这将导致当我们从a
开始遍历列表时,我们将在reversedB
结束(我们将返回a -> firstElementOfC -> reversedB
) . 这将为我们提供三个方程式,使我们可以获得公共部分的长度c
.这对于编程比赛或在制作中使用来说太慢了,但我认为这种方法很有趣 .
也许在这一点上无关紧要,但这是我的脏递归方法 . 这需要
O(M)
时间和O(M)
空间,其中M >= N
为list_M
长度M
和list_N
长度N
递归迭代到两个列表的末尾,然后从步骤
2
开始计数 . 请注意list_N
将在list_M
之前命中null
,因为M > N
相同长度
M=N
在list_M != list_N && list_M.next == list_N.next
时相交不同长度
M>N
在list_N != null
时相交代码示例: