多个数组求交集

标签: 数组 哈希表 计数 排序

难度: Easy

给你一个二维整数数组 nums ,其中 nums[i] 是由 不同 正整数组成的一个非空数组,按 升序排列 返回一个数组,数组中的每个元素在 nums 所有数组 中都出现过。

示例 1:

输入:nums = [[3,1,2,4,5],[1,2,3,4],[3,4,5,6]]
输出:[3,4]
解释:
nums[0] = [3,1,2,4,5],nums[1] = [1,2,3,4],nums[2] = [3,4,5,6],在 nums 中每个数组中都出现的数字是 3 和 4 ,所以返回 [3,4] 。

示例 2:

输入:nums = [[1,2,3],[4,5,6]]
输出:[]
解释:
不存在同时出现在 nums[0] 和 nums[1] 的整数,所以返回一个空列表 [] 。

提示:

  • 1 <= nums.length <= 1000
  • 1 <= sum(nums[i].length) <= 1000
  • 1 <= nums[i][j] <= 1000
  • nums[i] 中的所有值 互不相同

Submission

运行时间: 24 ms

内存: 16.3 MB

class Solution:
    def intersection(self, nums: List[List[int]]) -> List[int]:
        if nums is None or len(nums) == 0:
            return []
        if len(nums) == 1:
            nums[0].sort()
            return nums[0]
        output = set(nums[0])
        for num in nums[1:]:
            output = output.intersection(set(num))
        output = list(output)
        output.sort()
        return output

Explain

此题解方法首先确认输入数组是否为空或null,如果满足上述任一条件,直接返回空数组。如果数组只包含一个子数组,直接返回该数组(题目已保证子数组内元素不重复且已排序)。接下来,算法以第一个子数组初始化一个集合作为交集的基础,然后遍历剩余的子数组,利用集合的intersection方法来更新交集。最后,将得到的交集集合转换为列表,并进行排序(虽然题目中子数组已排序,但集合操作后元素顺序可能改变),然后返回排序后的列表。

时间复杂度: O(n + m log m)

空间复杂度: O(m)

class Solution:
    def intersection(self, nums: List[List[int]]) -> List[int]:
        # 检查nums是否为空或None
        if nums is None or len(nums) == 0:
            return []
        # 处理只有一个子数组的情况
        if len(nums) == 1:
            return nums[0]
        # 使用第一个子数组的元素初始化交集集合
        output = set(nums[0])
        # 遍历剩余子数组,更新交集
        for num in nums[1:]:
            output = output.intersection(set(num))
        # 将交集转为列表并排序
        output = list(output)
        output.sort()
        # 返回排序后的交集
        return output

Explore

在输入为多个空子数组的情况下,根据题解逻辑,应该返回空数组。原因是这些空子数组实际上没有任何元素,因此不存在任何可以构成交集的元素。虽然题解的初衷是处理非空数组,但空子数组在逻辑上应当返回空数组,因为交集是指所有数组中共同出现的元素,空集之间无共同元素,故结果应为空数组。

使用集合(set)来处理交集而不使用列表(list)的主要原因是效率。集合在Python中是基于哈希表实现的,因此查找、插入和删除操作的平均时间复杂度为O(1)。使用集合的`intersection`方法来计算交集特别高效,因为它可以快速检查和比对元素是否存在于其他集合中。而相对地,如果使用列表,检查一个元素是否存在于列表中需要O(n)的时间复杂度,这会使得整体算法效率降低,特别是在处理大量数据时更为明显。

虽然输入的子数组是排序的,但在使用集合进行交集操作时,集合内部的元素顺序是不确定的,因为集合是无序的数据结构。尽管可以考虑使用有序数据结构(如有序集合或在列表中维护有序状态)来避免最后的排序操作,但这通常会牺牲一些性能,因为维护元素的有序状态(特别是在交集操作中)可能比简单地在最后进行排序更复杂或更耗时。因此,在效率和简单性的权衡下,选择在最后对结果列表进行排序是一个实用的解决方案。

对于只有一个子数组的情况,直接返回这个子数组是符合题目要求的。因为当只存在一个子数组时,该子数组的所有元素自然是出现在所有(即唯一一个)子数组中的。因此,这种实现完全符合题目要求的返回格式,即返回一个包含所有在给定子数组中共同出现的元素的数组。