题目描述
分析
给定两个已排序的列表,直接用集合求交集是一个自然的选择。集合的交集操作非常高效,可以在常数时间内判断元素是否在集合中。然而,计算交集后,我们还需要将结果按从大到小的顺序排列。排序操作会占用一定的时间,特别是当交集元素较多时,效率可能会受到影响。
解法一
- 转换为集合:由于集合的查找和插入操作是 O(1) 的,我们可以把列表
a和b转换为集合,快速找出它们的交集。 - 求交集:使用
set_a & set_b操作,找到交集元素。 - 排序:使用
sorted函数将交集结果按从大到小排序。
代码实现如下:
def solution(a, b):
# 将列表转换为集合
set_a = set(a)
set_b = set(b)
# 求交集
intersection = set_a & set_b
# 排序交集,按从大到小的顺序
result = sorted(intersection, reverse=True)
return result
这段代码的核心在于集合的交集操作,时间复杂度为 O(min(len(a), len(b)))。但是排序操作的时间复杂度是 O(n log n),其中 n 是交集元素的数量。如果交集元素较少,这种方法的效率已经非常高了。
解法二
虽然集合操作本身很高效,但我们可以进一步优化代码,减少不必要的计算。
由于输入列表已经是有序的,可以利用双指针法在不转换为集合的情况下直接求交集。双指针法的优势在于,它可以在线性时间内求解交集,并且不需要额外的空间来存储集合。
具体做法如下:
-
初始化两个指针,分别指向列表
a和b的开头。 -
比较两个指针所指向的元素:
- 如果相等,将该元素加入交集,两个指针都向后移动。
- 如果
a[i] < b[j],则a的指针向后移动。 - 如果
a[i] > b[j],则b的指针向后移动。
-
最终得到交集,直接进行排序。
这种方法的时间复杂度是 O(len(a) + len(b)),没有额外的空间开销。
代码实现:
def solution(a, b):
i, j = 0, 0
intersection = []
# 双指针法求交集
while i < len(a) and j < len(b):
if a[i] == b[j]:
intersection.append(a[i])
i += 1
j += 1
elif a[i] < b[j]:
i += 1
else:
j += 1
# 排序交集,从大到小
return sorted(intersection, reverse=True)
对比分析
- 集合法:通过集合求交集,转换集合的时间复杂度是 O(len(a) + len(b)),交集操作是 O(min(len(a), len(b))),然后排序的时间复杂度是 O(n log n)。整体时间复杂度为 O(min(len(a), len(b)) + n log n),其中 n 是交集的元素数量。
- 双指针法:双指针法的时间复杂度是 O(len(a) + len(b)),不需要转换为集合,也不需要额外的内存开销,适合大数据量时使用。
总结
对于本问题,最常见的做法是先将列表转换为集合,然后求交集并排序。这种方法简单且有效,但如果输入数据量很大,双指针法可能会更高效,因为它避免了集合的额外转换和内存消耗。
- 当交集元素较少时,使用集合法更为简单。
- 当交集较大或数据量较大时,双指针法更为高效,尤其是在不需要额外空间的情况下。
但是暴力法能过,所以……