多个排序数组求交集

如果有多个已经按照从小到大排序的数字数组,如何快速的获取这些数组元素交集,即找到一个子集合在所有的数组中都出现。 

 


解决办法: 
(1)找到最短的数组v[i]作为标准数组。目标集合x必然是v[i]的子集合 
(2)如果v[i]中的某个元素v[i][j] 在所有数组中都出现,那么设定stat[i]=v.size()-1; 
stat[i]是状态数组。表示v[i][j]在多少个数组中出现。 
  
(3) 用二分查找算法,在v[1]数组中查找 v[i][j]是否出现。 
   如果出现:那么在v[2]中查找; 
   否则:v[i][j]不是目标元素。 
   当v[n]中都有v[i][j],那么输出v[i][j]; 
(4)注意:

   当在v[1]中查找 v[i][j+1]的时候,比 v[i][j]小的部分不用再查询了。
应用场景: 
   搜索引擎的And搜索结果的索引合并 

<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)) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值