【数论】C022_LC_两个数组的交集 II(map计数 / 双指针)

一、题目

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

输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [4,9]
说明:
1、输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。
2、我们可以不考虑输出结果的顺序。

进阶:

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

二、分析

暴力就不写了,没啥技术含量。说下关键:在枚举时,外层为长数组,内层为短数组。

方法一:Map 计数

Map 的 key 记录第一个数组中的元素的值,value 记录出现的次数。

class Solution {
public:
    vector<int> intersect(vector<int>& A, vector<int>& B) {
        vector<int> ans;
    	unordered_map<int, int> m1, m2;
    	for (int a : A) m1[a]++;
		for (int b : B) m2[b]++;

		for (int a : A) if (m1[a] && m2[a]) {
            int mi = min(m1[a], m2[a]);
            while (mi--) {
                ans.push_back(a);
                m1.erase(a), m2.erase(a);
            }
        }
    	return ans;
    }
};

优化:不是用两个 map,而是用减法遍历第二个数组,如果找到对应元素 && 对应 HashMap 中的 value 不为 0,则添加这个元素到 list 中。同时,HashMap 中的 value 值减一,表示已经找到 1 个相同的数。

class Solution {
public:
    vector<int> intersect(vector<int>& A, vector<int>& B) {
        vector<int> ans;
    	unordered_map<int, int> m;
    	for (int a : A) m[a]++;

		for (int b : B) if (m[b]) {
			ans.push_back(b);
			m[b]--;
        }
    	return ans;
    }
};

复杂度分析

  • 时间复杂度: O ( s i z e 1 + s i z e 2 ) O(size1 + size2) O(size1+size2)
  • 空间复杂度: O ( m i n ( s i z e 1 + s i z e 2 ) ) O(min(size1 + size2)) O(min(size1+size2)),我们对较小的数组进行哈希映射使用的空间。

方法二:双指针

思路

  • 如果数组排好序,那么我采取双指针 p 1 、 p 2 p1、p2 p1p2 对两个数组逐个遍历.
  • 如果找到相同的元素,那么指针 p1、p2 都移到下一个位置.
  • 相比之下,如果数组1的值 nums1[p1] > nums2[p2],那么我们可以做出判断–> “要找的元素” 应该在此刻 nums1 元素的后面。所以我们只让 p1 移动。相反亦然。

复杂度分析

  • 时间复杂度: O ( m a x ( s i z e 1   l o g   s i z e 1 , s i z e 2   l o g   s i z e 2 ) O(max(size1\ log\ size1,size2\ log\ size2) O(max(size1 log size1size2 log size2)
  • 空间复杂度: O ( m i n ( s i z e 1 + s i z e 2 ) ) O(min(size1 + size2)) O(min(size1+size2))

进阶:数组在磁盘中

思路

如果内存十分小,不足以将数组全部载入内存,那么必然也不能使用哈希这类费空间的算法。

一般说排序算法都是针对于内部排序,一旦涉及到磁盘(外部排序)。归并排序是天然适合外部排序的算法,可以将分割后的子数组写到单个文件中,归并时将小文件合并为更大的文件。 当两个数组均排序完成生成两个大文件后,即可使用双指针遍历两个文件,如此可以使空间复杂度最低。

关于外部排序与 JOIN,强烈推荐大家看一下 数据库内核杂谈(六):表的 JOIN(连接)这一系列数据库相关的文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值