方法一:哈希表
方法二:排序+双指针
class Solution:
def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
# 方法一:O(n)
hashmap = {}
for i in nums1:
if i in hashmap:
hashmap[i] += 1
else:
hashmap[i] = 1
res = []
for j in nums2:
if j in hashmap:
res.append(j)
hashmap[j] -= 1 # 每次-1, 为0时弹出
if hashmap[j] == 0:
hashmap.pop(j)
return res
# 方法二:排序+双指针 O(nlogn+n)
# res = []
# i, j = 0, 0
# nums1.sort()
# nums2.sort()
# while i < len(nums1) and j < len(nums2):
# if nums1[i] == nums2[j]:
# if not res or nums1[i] != res[-1]:
# res.append(nums1[i])
# i += 1
# j += 1
# elif nums1[i] < nums2[j]:
# i += 1
# else:
# j += 1
# return res
哈希表:复杂度分析
- 时间复杂度: O ( m + n ) O(m+n) O(m+n),其中 m m m 和 n n n 分别是两个数组的长度。需要遍历两个数组并对哈希表进行操作,哈希表操作的时间复杂度是 O ( 1 ) O(1) O(1),因此总时间复杂度与两个数组的长度和呈线性关系。
- 空间复杂度: O ( min ( m , n ) ) O(\min(m,n)) O(min(m,n)),其中 m m m 和 n n n 分别是两个数组的长度。对较短的数组进行哈希表的操作,哈希表的大小不会超过较短的数组的长度。为返回值创建一个数组 res,其长度为较短的数组的长度。
排序+双指针:复杂度分析
-
时间复杂度: O ( m log m + n log n ) O(m \log m+n \log n) O(mlogm+nlogn),其中 m m m 和 n n n 分别是两个数组的长度。对两个数组进行排序的时间复杂度是 O ( m log m + n log n ) O(m \log m+n \log n) O(mlogm+nlogn),遍历两个数组的时间复杂度是 O ( m + n ) O(m+n) O(m+n),因此总时间复杂度是 O ( m log m + n log n ) O(m \log m+n \log n) O(mlogm+nlogn)。
-
空间复杂度: O ( min ( m , n ) ) O(\min(m,n)) O(min(m,n)),其中 m m m 和 n n n 分别是两个数组的长度。为返回值创建一个数组 res,其长度为较短的数组的长度。不过在 C++ 中,我们可以直接创建一个 vector,不需要把答案临时存放在一个额外的数组中,所以这种实现的空间复杂度为 O ( 1 ) O(1) O(1)。
结语:如果 n u m s 2 nums_2 nums2 的元素存储在磁盘上,磁盘内存是有限的,并且你不能一次加载所有的元素到内存中。那么就无法高效地对 n u m s 2 nums_2 nums2 进行排序,因此推荐使用方法一而不是方法二。在方法一中, n u m s 2 nums_2 nums2 只关系到查询操作,因此每次读取 n u m s 2 nums_2 nums2 中的一部分数据,并进行处理即可。