LeetCode350.两个数组的交集 II

文章介绍了如何使用multiset和双指针法、map来找到两个整数数组的交集,考虑了元素出现次数和已排序数组的优化策略,并讨论了在内存限制下处理大数组的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

350.两个数组的交集 II


题目

给你两个整数数数组 nums1nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。

示例 1:

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

示例 2:

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

提示:

  • 1 <= nums1.length, nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 1000

*进阶*

  • 如果给定的数组已经排好序呢?你将如何优化你的算法?
  • 如果 nums1 的大小比 nums2 小,哪种方法更优?
  • 如果 nums2 的元素存储在磁盘上,内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?

解法

方法一:通过multiset+双指针法

题目要求找到两个数组的交集,并且交集中的元素需要考虑出现的次数。可以使用 multiset 数据结构来解决这个问题。

首先,代码中创建了两个 multiset 对象 mul1mul2,并将输入的 nums1nums2 分别插入到这两个集合中。由于 multiset 允许重复元素,所以相同的元素会被正确地添加到集合中,并保持出现的次数。

然后,使用两个迭代器 it1it2 来分别遍历 mul1mul2。在 while 循环中,首先比较迭代器指向的元素大小,如果 *it1 < *it2,则说明 mul1 中的元素小于 mul2 中的元素,此时将 it1 向后移动一位。如果 *it1 > *it2,则将 it2 向后移动一位。如果 *it1*it2 相等,则将这个相同的元素添加到结果向量 result 中,并且同时将 it1it2 向后移动一位。

最后,返回结果向量 result,其中包含了两个数组的交集元素。

对于进阶问题:

  • 如果给定的数组已经排好序,可以使用双指针的方法来优化算法。通过维护两个指针,分别指向 nums1nums2 的起始位置,根据元素的大小移动指针,可以避免创建额外的集合和迭代器。
  • 如果 nums1 的大小比 nums2 小,可以通过先将 nums1 转换为 multiset,然后遍历 nums2,只处理在 multiset 中出现过的元素,以减少内存消耗。
  • 如果 nums2 的元素存储在磁盘上且内存有限,可以考虑使用分块处理的方法。将 nums2 分成多个较小的块,在内存中逐块加载并与 nums1 进行比较,然后将交集的部分存储下来。最后,将每个块的交集进行合并得到最终的结果。这样可以避免一次性加载所有的元素到内存中。
class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        multiset<int> mul1(nums1.begin(),nums1.end());
        multiset<int> mul2(nums2.begin(),nums2.end());
        //此时mul1、mul2都是排好序的元素
        vector<int> result;
        auto it1 = mul1.begin(),it2 = mul2.begin();
        while(it1 != mul1.end() && it2 != mul2.end()){
            if(*it1 < *it2){
                it1++;
            }
            else if(*it1 > *it2){
                it2++;
            }
            else{
                result.push_back(*it1);
                it1++;
                it2++;
            }
        }
        return result;
    }
};

方法二:通过map

首先,创建一个 map<int, int> 对象 m 来统计 nums1 中每个元素的出现次数。通过遍历 nums1,使用自增操作符 m[num]++ 来对元素 num 的出现次数进行累加。

然后,通过遍历 nums2,使用 m.count(i) 来检查元素 i 是否存在于 m 中,以及 m[i] 是否大于 0,即元素 inums1 中出现的次数是否大于 0。这样可以确保交集中的元素在两个数组中都出现,并且按照较小的出现次数进行计数。如果满足条件,就将 m[i] 减 1,并将元素 i 添加到结果向量 result 中。

最后,返回结果向量 result,其中包含了两个数组的交集元素。

class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        map<int,int> m;
        vector<int> result;
        for(int num : nums1) m[num]++;  //统计nums1中各个元素的数量
        for(int i : nums2){
            if(m.count(i) && m[i]){	//如果i在m中存在且m[i]>0的情况下(其实把前半个条件去掉也行)
                m[i]--;
                result.push_back(i);
            }
        }
        return result;
    }
};

一些拓展

两个数组的交集问题的应用

两个数组的交集问题在实际开发中有一些应用场景。下面是其中的一些例子:

数据库查询:在数据库查询中,我们经常需要对多个表进行联合查询,找到满足特定条件的交集记录。这个问题可以通过将数组中的元素作为查询条件,并将查询结果进行交集操作来解决。

好友推荐:在社交网络中,好友推荐是一个常见的功能。通过分析用户的兴趣、关注的人和活动等信息,可以找到与用户有相似兴趣的人,并将其推荐给用户。在这个过程中,可以使用两个数组的交集操作来找到共同关注的人或共同参加的活动。

数据分析:在数据分析中,我们经常需要对多个数据集进行合并和分析。通过找到两个数据集的交集,可以获取到共同的数据项,从而进行更准确的分析和预测。

优化思路:已排序数组的进一步优化

在题目的进阶部分,提到了如果给定的数组已经排好序,可以如何优化算法。

对于已排序的数组,我们可以使用双指针的方法来进一步优化算法。通过维护两个指针,分别指向 nums1 和 nums2 的起始位置,根据元素的大小移动指针,可以避免创建额外的集合和迭代器。

内存限制下的优化

在题目的进阶部分,还提到了如果 nums2 的元素存储在磁盘上,内存是有限的,并且不能一次性加载所有的元素到内存中,应该如何处理。

对于这种情况,可以考虑使用分块处理的方法。将 nums2 分成多个较小的块,在内存中逐块加载并与 nums1 进行比较,然后将交集的部分存储下来。最后,将每个块的交集进行合并得到最终的结果。这样可以避免一次性加载所有的元素到内存中,同时还能有效地处理大规模数据的交集问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KeepCoding♪Toby♪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值