【算法】求多个数组中的交集(Java语言实现)
简介:
最近在工作中遇到一个问题,需要离线比较两张Mongodb表的差异:大小差异,相同的个数。
所以,我将导出的bson文件转成了json文件(2G以上),一条记录正好是一行。
问题:
因此我将以上问题转换成了比较两个(本例考虑多个)超大数组的交集!所以要求时间复杂度、空间复杂度应该尽可能的低!
降低内存:
由于要将文件的每一行都读到内存里,如果行的长度比较大的话,内存肯定是不够的!
所以我想到的办法是讲每一行压缩成md5编码。 String line = md5(line)。然后再将新的line读入内存。
如此,通常1000万行记录读到内存里大概是800MB(这里有点忘了,反正大概是800MB~1GB)。
(我使用的idea编辑器,跟eclipse可能在某些地方有点差别。另外,本例一字符数组为例,并且假设数组元素不重复!!!)
MapReduce:
/** * 这里以字符串数组为例 * 采用mapreduce原理,生成一组以数组元素为key,相同元素的个数为value的中间键值对 * 这里将mapreduce分开来写方便阅读,也可以写成一个函数 * @param arrays */ public static HashMap<String, Integer> mapReduce(final String[]... arrays) { HashMap<String, Integer> hashMap = new HashMap<>(); // 不要看到两个for就以为时间复杂度为n^2,这里只是有多个数组参数而已 for (String[] array : arrays) { for (String elem : array) { if (hashMap.containsKey(elem)) { hashMap.put(elem, hashMap.get(elem) + 1); } else { hashMap.put(elem, 1); } } } return reduce(hashMap, arrays.length); }
Reduce:
/** * 统计出相同元素个数正好是数组(参数)个数的元素(也就是每个数组中都有的元素) * 移除value不等于数组参数个数的键值对,并组成新的map * @param hashMap * @param arrayCount * @return */ public static HashMap<String, Integer> reduce(HashMap<String, Integer> hashMap, final Integer arrayCount) { Iterator<String> iter = hashMap.keySet().iterator(); String key; while(iter.hasNext()) { key = iter.next(); if (!hashMap.get(key).equals(arrayCount)) {
// 不能使用 hashMap.remove(key); 会出现异常, 见http://www.cnblogs.com/yrqiang/p/5344531.html iter.remove(); } } return hashMap; }
eg:
/** * 本例假设同一数组中的元素不重复 * @param args */ public static void main(String[] args) { HashMap<String, Integer> hashMap = new HashMap<>(); String[] arr1 = {"aa", "bb", "cc", "dd"}; String[] arr2 = {"11", "bb", "cc", "dd", "ee"}; String[] arr3 = {"22", "bb", "cc", "dd", "ee", "ff"}; hashMap = mapReduce(arr1, arr2, arr3); System.out.println(hashMap); System.out.println(hashMap.size()); }