<think>我们已知两个有序链表,要求交集,并以有序链表形式返回。
思路:双指针法。由于链表有序,我们可以同时遍历两个链表,比较当前节点的值。
如果两个值相等,则加入结果链表,并同时移动两个指针。
如果其中一个值小于另一个,则移动较小值对应的指针。
重复直到其中一个链表遍历完毕。
注意:题目要求交集,即两个链表都出现的元素。而且由于链表有序,结果自然有序。
根据引用[1]中的思路和算法步骤,我们用Python实现如下:
首先定义链表节点类:
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
然后实现函数get_intersection(headA, headB):
初始化一个哨兵节点dummy,用于简化结果链表的操作。
用tail指针指向结果链表的尾部,方便添加新节点。
初始化两个指针pA和pB分别指向两个链表的头节点。
循环条件:pA和pB均不为空。
比较pA.val和pB.val:
相等:则新建一个节点,值为pA.val(或pB.val),添加到结果链表尾部,然后同时移动pA和pB。
pA.val < pB.val:则移动pA(pA = pA.next)
pA.val > pB.val:则移动pB(pB = pB.next)
返回dummy.next(即结果链表的头节点)
注意:由于两个链表都是有序的,所以这样得到的交集链表也是有序的。
另外,引用[2]中提到了一个注意点:交集是重复元素只取一次吗?但是实际上,如果两个链表都有重复的元素,那么交集应该包含重复的次数是多少?题目并没有明确,但通常交集是指两个集合都出现的元素,而且集合中元素不重复。但是本题是链表序列,序列中可能有重复元素。根据引用[1]中的示例代码,当遇到相等元素时,只添加一次,然后两个指针同时后移。这样处理,对于重复元素,例如:
链表A: 1->1->2->3
链表B: 1->1->3->4
那么交集应该是:1(出现两次)->3(出现一次)?还是1->1->3?
但是,引用[1]的示例代码中,当两个指针指向的节点都为1时,只添加一个1,然后两个指针同时后移。这样得到的交集是1->3。
然而,题目要求的是“交集元素”,通常是指集合的交集,即不重复。但是题目描述为“两个有序链表序列的交集”,序列中可能有重复。我们需要根据题目的要求来。
观察引用[3]中,题目要求是“新链表为空,输出NULL”,并且输入输出样例中并没有重复元素的情况。另外引用[2]中特别提到:“注意22 和22的交集是22不是2啊啊啊啊啊”,并且代码中有一个cnt计数,说明在引用[2]的题目中,要求重复元素只出现一次?还是出现多次?实际上,引用[2]的代码中,当遇到重复元素时,只添加一次,并且通过一个cnt标记来避免重复添加?但是这里我们不是用同一个链表节点,而是新建节点,所以重复元素应该如何处理?
重新审题:题目要求“交集元素”,通常是指两个集合的交集(不重复)。所以,即使原链表有重复,交集链表中每个元素只出现一次。因此,我们按照引用[1]的方法:每次相等添加一个新节点,然后两个指针都后移,这样重复元素只会被添加一次。例如上面的例子,得到1->3。
但如果题目要求考虑重复次数,例如交集元素在两个链表中出现的最小次数?那么上面的例子就应该得到1->1->3。但是题目没有明确说明,通常题目都是按照集合的交集(无重复)处理,所以我们就按无重复处理。
因此,我们的实现如下:
</think>要使用Python实现两个有序链表序列的交集,可以使用高效的双指针法。该方法时间复杂度为$O(m+n)$,空间复杂度为$O(1)$(不考虑结果链表存储)。以下是完整实现:
```python
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def get_intersection(headA, headB):
# 创建哨兵节点简化操作
dummy = ListNode(-1)
tail = dummy
pA, pB = headA, headB
while pA and pB:
if pA.val == pB.val:
# 添加交集元素到新链表
tail.next = ListNode(pA.val)
tail = tail.next
pA = pA.next
pB = pB.next
elif pA.val < pB.val:
pA = pA.next
else:
pB = pB.next
return dummy.next # 返回交集链表的头节点
# 辅助函数:创建链表
def create_linked_list(lst):
dummy = ListNode()
current = dummy
for val in lst:
current.next = ListNode(val)
current = current.next
return dummy.next
# 辅助函数:打印链表
def print_list(head):
if not head:
print("NULL")
return
result = []
while head:
result.append(str(head.val))
head = head.next
print("->".join(result))
# 测试示例
if __name__ == "__main__":
# 创建链表A: 1->2->4->6
listA = create_linked_list([1, 2, 4, 6])
# 创建链表B: 2->4->6->8
listB = create_linked_list([2, 4, 6, 8])
# 获取交集
result = get_intersection(listA, listB)
print_list(result) # 输出: 2->4->6
```
### 算法详解:
1. **双指针遍历**
- 初始化指针 `pA` 和 `pB` 分别指向两个链表头部
- 比较当前节点值:
- 相等时:将值添加到结果链表,两指针同时后移
- `pA.val < pB.val`:仅 `pA` 后移
- `pA.val > pB.val`:仅 `pB` 后移
- 当任一指针到达链表末尾时终止
2. **哨兵节点优化**
使用 `dummy` 节点作为结果链表头前驱,避免特殊头节点处理
3. **有序性利用**
因输入链表有序,结果链表自然有序,无需额外排序[^1]
### 关键点说明:
- **重复元素处理**:当原链表有重复值时(如两个链表都有两个`2`),结果链表只输出一个`2`(集合语义的交集)
- **复杂度**:时间复杂度 $O(m+n)$,空间复杂度 $O(k)$($k$=交集元素数量)
- **边界处理**:当任一链表为空时直接返回`None`
### 测试用例示例:
```python
# 用例1:有交集
listA = [1, 3, 4, 7]; listB = [2, 3, 7, 9]
# 输出:3->7
# 用例2:无交集
listA = [1, 2, 3]; listB = [4, 5, 6]
# 输出:NULL
# 用例3:含重复值
listA = [1, 2, 2, 3]; listB = [2, 2, 4]
# 输出:2(仅一个)
```
此实现完整遵循有序链表交集的经典算法[^1][^2],通过双指针同步扫描避免了低效的嵌套循环,适合处理大规模有序数据。