Python面试宝典第36题:数组的交集

121 阅读4分钟

题目

给定两个数组nums1和nums2,返回它们的交集 。输出结果中的每个元素一定是唯一的,我们可以不考虑输出结果的顺序。

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]

示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4] 或 [4,9]

哈希法

使用哈希法求解两个数组的交集是一个非常高效的方法,其基本思想为:使用哈希表(或集合)存储一个数组中的所有元素,然后遍历另一个数组,检查其中的元素是否出现在哈希表中。使用哈希法求解本题的主要步骤如下。

1、创建哈希表。遍历第一个数组nums1,将所有元素添加到哈希表中。

2、查找交集。遍历第二个数组nums2,检查每个元素是否在哈希表中。

3、收集结果。如果元素存在于哈希表中,则将其添加到结果列表中。同时,从哈希表中移除该元素,以避免重复添加。

4、返回收集到的结果列表。

根据上面的算法步骤,我们可以得出下面的示例代码。

def array_intersection_by_hash(nums1, nums2):
    result = []
    # 使用集合存储nums1中的元素
    hash_set = set(nums1)

    # 遍历nums2中的每个元素
    for num in nums2:
        # 如果元素存在于哈希表中
        if num in hash_set:
            # 添加到结果列表中
            result.append(num)
            # 从哈希表中移除该元素,以避免重复
            hash_set.remove(num)

    return result

nums1 = [1, 2, 2, 1]
nums2 = [2, 2]
print(array_intersection_by_hash(nums1, nums2))

nums1 = [4, 9, 5]
nums2 = [9, 4, 9, 8, 4]
print(array_intersection_by_hash(nums1, nums2))

双指针法

使用双指针法求解两个数组的交集也是一种效率较高的方法,尤其是在两个数组都已经排序的情况下。对于两个已排序的数组,可以通过双指针法找到它们的交集。这种方法的核心是:同时维护两个指针,一个指向第一个数组中的元素,另一个指向第二个数组中的元素。通过比较这两个指针所指向的元素值,可以有效地找到交集中的元素。使用双指针法求解本题的主要步骤如下。

1、排序数组。如果输入数组未排序,则先对两个数组进行排序。

2、分别为两个数组初始化指针i和j。

3、比较元素。比较两个指针所指向的元素,进行以下操作。

(1)如果两个元素相等,且该元素不同于上一个加入结果集的元素,则加入结果集。

(2)如果nums1[i] < nums2[j],则移动nums1的指针i。

(3)如果nums1[i] > nums2[j],则移动nums2的指针j。

4、继续遍历。重复步骤3,直到遍历完任一阵列。

5、返回收集到的结果列表。

根据上面的算法步骤,我们可以得出下面的示例代码。

def array_intersection_by_two_pointers(nums1, nums2):
    result = []
    # 先对两个数组进行排序
    nums1.sort()
    nums2.sort()

    # 初始化两个指针
    i, j = 0, 0
    # 用于记录上一个加入结果集的元素
    prev = None

    # 遍历两个数组直到有一个数组遍历结束
    while i < len(nums1) and j < len(nums2):
        if nums1[i] == nums2[j]:
            # 如果当前元素与上一个加入结果集的元素不同,则加入结果集
            if nums1[i] != prev:
                result.append(nums1[i])
                prev = nums1[i]
            # 移动两个指针
            i += 1
            j += 1
        elif nums1[i] < nums2[j]:
            # 移动nums1的指针
            i += 1
        else:
            # 移动nums2的指针
            j += 1

    return result

nums1 = [1, 2, 2, 1]
nums2 = [2, 2]
print(array_intersection_by_two_pointers(nums1, nums2))

nums1 = [4, 9, 5]
nums2 = [9, 4, 9, 8, 4]
print(array_intersection_by_two_pointers(nums1, nums2))

内置函数

实际上,我们还可以使用Python的内置函数来求解本题。其原理与上面介绍的哈希法基本类似,这里就不再赘述了。使用内置函数求解本题的示例代码如下。

def array_intersection_by_builtin_func(nums1, nums2):
    return list(set(nums1) & set(nums2))

nums1 = [1, 2, 2, 1]
nums2 = [2, 2]
print(array_intersection_by_builtin_func(nums1, nums2))

nums1 = [4, 9, 5]
nums2 = [9, 4, 9, 8, 4]
print(array_intersection_by_builtin_func(nums1, nums2))

总结

使用哈希法求解本题时,构建哈希表的时间复杂度为O(n),遍历查找的时间复杂度为O(m),故总体时间复杂度为O(n + m)。其中,n是nums1的长度,m是nums2的长度。哈希法的优点是实现简单,且不依赖于输入数组是否有序。

使用双指针法求解本题时,排序的时间复杂度为O(nlogn) + O(mlogm),双指针遍历的时间复杂度为O(n + m),故总体时间复杂度为O(nlogn + mlogm)。对于排序后的数组,可以直接使用双指针法进行高效的查找。但其实现稍微复杂一些,需要考虑边界条件等各自情况。