Java 中两个已排序链表的交集

2024年9月10日 | 阅读10分钟

在本问题中,给定两个已排序的链表(按非递减顺序排序)。任务是找到这两个链表的交集,即找到同时存在于两个链表中的元素。

示例 1

输入

链表 1: 12 -> 13 -> 35 -> 40 -> 56 -> 89 -> 90 -> 92

链表 2: 9 -> 14 -> 15 -> 30 -> 40 -> 85 -> 90 -> 92

输出

40 -> 90 -> 92
元素 40、90 和 92 是同时存在于链表 1 和链表 2 中的共同元素。

让我们来看看解决这个问题的各种方法。

使用哑节点

该方法是在输出列表的开头使用一个哑节点或临时节点。尾指针是指向输出列表最后一个节点的指针,以便可以快速添加或追加新节点。临时节点为尾指针提供了一个可以指向的空间。请注意,最初,尾指针指向输出的哑节点。现在,任务是使用单个循环遍历给定的链表。请注意,如果任何一个链表被完全遍历,循环将终止。在循环中,使用了双指针方法。一个指针 ptr1 用于链表 1,另一个指针 ptr2 用于链表 2。有以下三种情况:

情况 1: ptr1 指向的值大于 ptr2 指向的值。

情况 2: ptr1 指向的值小于 ptr2 指向的值。

情况 3: ptr1 和 ptr2 指向的值相等。

对于情况 1,递增 ptr2 指向下一个节点。对于情况 2,递增 ptr1 指向下一个节点。对于情况 3,打印值并将两个指针都递增到指向下一个节点。在情况 3 中,我们必须处理包含相同值的节点。例如,

链表 1: 4 -> 4 -> 4 -> 4 -> 4 -> 4 -> 5

链表 2: 4 -> 4 -> 4-> 5

这里,情况 3 适用,因为两个链表的第一个节点都是 4。因此,我们打印值 4,并将 ptr1 和 ptr2 递增到指向下一个节点。然而,即使递增之后,ptr1 和 ptr2 都指向相同的值 4。因此,我们必须再次递增两个指针;但这次我们不会打印值 4,因为 4 已经打印过了,我们将继续递增指针,直到两个指针都指向值 5。

因此,输出是 4 和 5。请注意,这里的交集的工作方式与我们在“集合”章节中学习的交集的工作方式相同。

观察下面的程序。

文件名: LinkedListIntersection.java

输出

The first linked list is: 
12 13 35 40 56 89 90 92 

The second linked list is: 
9 14 15 30 40 85 90 92 

The common elements of the first & the second linked list are: 
40 90 92 

 

The first linked list is: 
4 4 4 4 4 5 

The second linked list is: 
4 4 4 5 

The common elements of the first & the second linked list are: 
4 5

时间复杂度: 上述程序的 time complexity 为 O(min(a, b)),其中 a 和 b 分别是链表 1 和 2 中存在的元素或节点的数量。

使用递归

使用递归也可以实现相同的功能。

文件名: LinkedListIntersection1.java

输出

The first linked list is: 
12 13 35 40 56 89 90 92 

The second linked list is: 
9 14 15 30 40 85 90 92 

The common elements of the first & the second linked list are: 
40 90 92 

使用哈希

众所周知,Java 中的 HashSet 只包含唯一元素;因此,我们可以利用此属性来查找给定两个链表中的公共元素。观察以下程序。

文件名: LinkedListIntersection2.java

输出

The first linked list is: 
12 13 35 40 56 89 90 92 

The second linked list is: 
9 14 15 30 40 85 90 92 

The common elements of the first & the second linked list are: 
40 90 92 

时间复杂度: 由于我们分别遍历两个链表,因此上述程序的 time complexity 为 O(a + b),其中 a 和 b 是给定链表中存在的节点总数。