<think>我们要计算两个数组的交集(即两个数组中均包含的元素),并返回结果数组(元素唯一,不考虑顺序)。
注意:结果中每个元素出现的次数应与该元素在两个数组中出现的次数一致(如果元素在数组中出现多次,则结果中应包含多次)。
例如:数组1 = [1,2,2,1],数组2 = [2,2],则交集为[2,2];数组1 = [4,9,5],数组2 = [9,4,9,8,4],则交集为[4,9](或[9,4])。
我们可以使用哈希表(字典)来记录第一个数组中每个元素出现的次数,然后遍历第二个数组,如果当前元素在字典中存在且计数大于0,则将其加入结果,并减少字典中的计数。
步骤:
1. 遍历第一个数组,统计每个元素出现的次数,存入字典。
2. 遍历第二个数组,对于每个元素,如果在字典中存在且计数大于0,则将该元素加入结果列表,并将字典中对应计数减一。
这样,我们就能得到两个数组的交集(包含重复元素)。
注意:如果要求结果中元素唯一(即去重后的交集),则做法不同。但根据问题描述,我们要求元素出现次数与两个数组中出现次数一致(即包含重复元素)。
因此,我们按照上述步骤实现。
示例代码:
```python
def intersect(nums1, nums2):
# 为了减少空间复杂度,我们选择遍历较小的数组来建立哈希表
if len(nums1) > len(nums2):
return intersect(nums2, nums1)
# 统计nums1中每个元素出现的次数
count_dict = {}
for num in nums1:
count_dict[num] = count_dict.get(num, 0) + 1
result = []
for num in nums2:
# 如果当前元素在字典中,且计数大于0
if num in count_dict and count_dict[num] > 0:
result.append(num)
count_dict[num] -= 1
return result
# 测试示例
print(intersect([1,2,2,1], [2,2])) # 输出 [2,2]
print(intersect([4,9,5], [9,4,9,8,4])) # 输出 [4,9] 或 [9,4]
```
如果两个数组已经排序,我们可以使用双指针法,这样空间复杂度可以降为O(1)(不考虑结果存储空间),时间复杂度为O(n)。
双指针法:
1. 将两个数组排序。
2. 初始化两个指针分别指向两个数组的起始位置。
3. 比较两个指针所指的元素:
- 如果相等,则加入结果,两个指针都向后移动一位;
- 如果不相等,移动较小元素的指针(因为数组有序,较小元素不可能再与另一个数组中的更大元素相等)。
4. 直到某一个指针到达数组末尾。
示例代码(已排序数组):
```python
def intersect_sorted(nums1, nums2):
nums1.sort()
nums2.sort()
i, j = 0, 0
result = []
while i < len(nums1) and j < len(nums2):
if nums1[i] == nums2[j]:
result.append(nums1[i])
i += 1
j += 1
elif nums1[i] < nums2[j]:
i += 1
else:
j += 1
return result
# 测试
print(intersect_sorted([1,2,2,1], [2,2])) # 输出 [2,2] 注意:这里输入数组未排序,所以需要先排序
# 实际上,对于[1,2,2,1]排序后为[1,1,2,2],和[2,2](排序后还是[2,2])进行双指针比较:第一个1小于2,i后移;第二个1小于2,i后移;第一个2等于2,加入结果,i和j后移;然后第二个2等于第二个2,加入结果。
```
注意:双指针法要求数组有序,如果数组未排序,则排序的时间复杂度为O(n log n),而哈希表法的时间复杂度为O(n)。
根据问题要求,我们提供了两种方法。用户可以根据数组是否有序以及内存限制选择合适的方法。
§§相关问题§§
1. 如果两个数组非常大且无法一次性加载到内存中,如何计算它们的交集?
2. 如何计算多个数组的交集?
3. 如果要求交集元素在结果中只出现一次(即去重),代码应如何修改?
4. 在双指针法中,如果两个数组已经排序,如何优化以减少不必要的比较?
5. 如何利用二分查找来解决一个数组较小而另一个数组非常大的情况?</think>### 两个数组求交集的方法
#### 1. 使用集合(适用于无重复元素)
```python
def intersection_simple(a, b):
return list(set(a) & set(b))
# 示例
arr1 = [1, 2, 3, 4, 5]
arr2 = [4, 5, 6, 7]
print(intersection_simple(arr1, arr2)) # 输出: [4, 5]
```
#### 2. 使用字典/哈希表(保留重复元素)
```python
from collections import defaultdict
def intersection_with_duplicates(a, b):
count_dict = defaultdict(int)
# 统计第一个数组的元素频率
for num in a:
count_dict[num] += 1
result = []
# 遍历第二个数组,匹配交集
for num in b:
if count_dict[num] > 0:
result.append(num)
count_dict[num] -= 1
return result
# 示例
arr3 = [1, 2, 2, 3, 4]
arr4 = [2, 2, 3, 5]
print(intersection_with_duplicates(arr3, arr4)) # 输出: [2, 2, 3]
```
#### 3. 双指针法(适用于已排序数组)
```python
def intersection_sorted(a, b):
a.sort()
b.sort()
i, j = 0, 0
result = []
while i < len(a) and j < len(b):
if a[i] == b[j]:
result.append(a[i])
i += 1
j += 1
elif a[i] < b[j]:
i += 1
else:
j += 1
return result
# 示例
arr5 = [1, 3, 5, 7, 9]
arr6 = [2, 3, 5, 8]
print(intersection_sorted(arr5, arr6)) # 输出: [3, 5]
```
#### 4. 使用Counter(简洁高效)
```python
from collections import Counter
def intersection_counter(a, b):
count_a = Counter(a)
count_b = Counter(b)
# 计算最小交集
intersection = count_a & count_b
# 展开为列表
return list(intersection.elements())
# 示例
arr7 = [1, 1, 2, 3, 4]
arr8 = [1, 2, 2, 4]
print(intersection_counter(arr7, arr8)) # 输出: [1, 2, 4]
```
### 方法比较
| 方法 | 时间复杂度 | 空间复杂度 | 特点 |
|------|-----------|------------|------|
| 集合 | O(m+n) | O(m+n) | 快速但丢失重复元素 |
| 字典 | O(m+n) | O(min(m,n)) | 保留重复元素 |
| 双指针 | O(m log m + n log n) | O(1) | 需先排序 |
| Counter | O(m+n) | O(min(m,n)) | 最简洁的实现 |
### 特殊场景处理
1. **大型数组处理**:
```python
def large_array_intersection(a, b):
# 使用生成器节省内存
count_a = Counter(a)
for num in b:
if count_a.get(num, 0) > 0:
count_a[num] -= 1
yield num
```
2. **多维数组交集**:
```python
def nested_array_intersection(a, b):
# 将嵌套数组转换为元组
set_a = {tuple(x) for x in a}
set_b = {tuple(x) for x in b}
return [list(x) for x in set_a & set_b]
```
3. **自定义对象交集**:
```python
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __hash__(self):
return hash((self.name, self.age))
def __eq__(self, other):
return self.name == other.name and self.age == other.age
def object_intersection(list1, list2):
return list(set(list1) & set(list2))
```