https://leetcode-cn.com/problems/intersection-of-two-arrays-ii/
单纯题目来看,如果没有进阶的第三个要求,这确实是一个简单的问题,我们先看看怎么解决前两问。
在本题中,测试用例显然是小数据,我们就可以使用STL中的unordered_map
的哈希表接口来解决了
因为两个数组的大小不一定相等的,我们每一次尽量让哈希表中的数据是比较少的,这样在哈希表中查找的速率就尽可能变小一点。
//哈希表技术
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
if(nums1.size() > nums2.size())
return intersect(nums2,nums1);
unordered_map<int,int> map;
for(auto& n : nums1)
map[n]++;
vector<int> ans;
for(auto& n : nums2)
if(map[n] > 0) ans.push_back(n),map[n]--;
return ans;
}
我们先对两个数组进行排序,然后用双指针的方式对两个数组依次遍历。
//排序
vector<int> intersect(vector<int>& nums1, vector<int>& nums2)
{
sort(nums1.begin(),nums1.end());
sort(nums2.begin(),nums2.end());
int le = 0,ri = 0;
vector<int> ans;
while(le < nums1.size() && ri < nums2.size())
{
if(nums1[le] == nums2[ri])
{
ans.push_back(nums2[ri]);
le++;
ri++;
continue;
}
//nums1[le] != nums2[ri]
if(nums1[le] < nums2[ri])
le++;
else
ri++;
}
return ans;
}
这个时候,因为num2数组
的数据在磁盘中,显然num1数组
是可以在内存中的,所以我们采取的方法是第一个哈希映射
的方式。
我们先对num1数组
进行哈希映射,然后依次从磁盘中读取num2
中的元素就可以。
因为num2
的数据量比较大,所以我们可以在查找的时候,判断哈希表是否为空
break
num2的数据
参考上一篇哈希位图与布隆过滤器
首先,因为磁盘中的数据过多,又因为int型数据最大只有42亿多,所以说磁盘中的数据是肯定存在重复的,所以说我们可以采用哈希位图
的方式对num1数组中的数据建立索引。
这里有一个需要注意的点,就是如果我们用一个位(1和0)来表示一个数据是否存在的话,我们是无法知道这个数据出现了多少次,所以我们可以用多个位来表示一个数据是否出现。
道理都是一样的,选择用多少个位来表示一个数据的时候,可以根据具体情况而定
这是对于数值类型的数据,我们采用位图的方式。那么对于字符串类型的数据,我们可以采用下面的方式:
为什么是近似求解呢
因为布隆过滤器判断一个数是否出现,这个一个概率的结果
另外布隆过滤器不支持删除操作,防止误判
然后采用的方式也是方法一的哈希映射。不同的是,这里的哈希表变成了哈希位图,因为数据量很大
对于精确算法,因为我们使用哈希位图映射的方式的时候,我们可以把那么多的数据根据不同的计算结果区分开,那么我们是否可以采用分治的算法呢?
我们采用这种方式,就可以把原本磁盘中很多的数据,分成同一个哈希地址的数据,将这些数据根据他们的哈希地址存储在一个磁盘中文件中
然后对于num2
在磁盘中的数据,我们依次进行遍历,然后计算哈希地址,依次在对应的文件中进行查找。
但是我们如果直接进行查找的话,在文件中的查找速率为O(n)
,这样下来,其实总体上还是一个O(n^2)
的算法,这是不可取的。
所以说我们可以在文件中的数据放在一个set容器
中,这样我们进行查找就是一个O(log n)
的时间复杂度,因为set容器的底层是一个红黑树。