[LeetCode] 350. 两个数组的交集 II

350. 两个数组的交集 II

给定两个数组,编写一个函数来计算它们的交集。

在这里插入图片描述
解题思路: 本题虽然标记的是Easy,但是此题进阶第3点提的要求非常有趣,值得好好解一下。OK,先介绍磁盘内存不受限的解法,i.e.,所有要处理的数据均可一次加载到内存中,那么首先对两个序列继续排序,然后用双指针分别指向两个序列的元素,当元素相当时候,则找到交集中的一个元素,指针同时挪动,若两个元素不相等,那么移动较小元素对应的指针。解此题的关键是要想到排序+双指针,那如果在思维混沌时想到这两个组合呢,遇到思路一时阻塞的题,我们本能的会尝试手动模拟的方式解题,即,如何求序列交集,那么我们最自然想法是拿着一个序列中的元素,去另一个序列中找是否有与它相同的元素(双指针的思想),OK,那会有什么问题吗,算法时间复杂度为很高,i.e., O ( n 2 ) O(n^2) O(n2),算法的开销主要在查找,OK,我们学过当序列有序时,查找效率可以降低为 O ( l o g n ) O(logn) O(logn),至此,思路即可打开,然后我们想一下怎么使用双指针找有序序列的交集,设计**双指针算法的关键是,两个指针,每次移动时,轮到谁移动。**然后回到此题,在排序完毕后,利用双指针对每个序列只用遍历一次即可解题,当元素相当时,自然找到交集元素,当元素不相等时,我们移动较小的元素意味着,我们希望较小的元素变大后能与另一个较大的元素相当,以期找到一个交集元素。OK,请看代码。

// 将两个数组排序,然后用双指针解题
// Time: O(nlogn), space:O(1)
class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        sort(nums1.begin(), nums1.end());
        sort(nums2.begin(), nums2.end());
        int i = 0, j = 0, n = nums1.size(), m = nums2.size();
        vector<int> res;
        while (i < n && j < m) {
            if (nums1[i] == nums2[j]) {
                res.push_back(nums1[i]);
                ++i, ++j;
            } else if (nums1[i] > nums2[j]) ++j;
            else ++i;
        }
        return res;
    }
};

Follow up中提了一个有趣的要求,磁盘内存不足,该如何优化算法,其实这句话我们换个说法,题目要求我们不能一次将nums2数据全部加载到内存中,那么对应到上述题解,对nums2的排序就不能work了,那么我们需要采取迭代的解法,即每次从nums2中获取一个元素参与求交集。由于交集中元素的个数要与两个序列对应,因此已经求得的交集元素要在两个序列中删除,为了加速查找,这里使用了multiset(允许元素重复)。

class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        vector<int> res;
        multiset<int> ms(nums1.begin(), nums1.end());
        for (auto num : nums2) {
            if (ms.count(num) != 0) {
                res.push_back(num);
                auto it = ms.find(num);
                ms.erase(it);
            }
        }
        return res;
    }
};

—————————————
参考资料:

https://en.cppreference.com/w/cpp/container/multiset

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值