在非常大的数据集中查找重复项 [重复]
Posted
技术标签:
【中文标题】在非常大的数据集中查找重复项 [重复]【英文标题】:Find a duplicate in an extremely large data set [duplicate] 【发布时间】:2017-08-23 17:55:03 【问题描述】:最近,我在一次采访中被问到以下问题。
Q : 给定一个 N 个整数,其中只有一个是重复的,找出那个重复的数。
我回答了一个解决方案,该解决方案将数字存储在哈希图中,并通过检查是否存在密钥来查找重复项。
他接着说如果数据集非常大,大到不能像连续流一样存储在内存中怎么办?
这有点难倒我。有人可以提出一些答案吗?另外,对于原始问题,除了哈希图之外,还有更有效的解决方案吗?
TIA
【问题讨论】:
" 有人可以提出一些答案吗?另外,对于原始问题,除了哈希图之外,还有更有效的解决方案吗?"不是 *** 的合适问题。这是一个有趣的问题,但它更适合讨论论坛而不是问答网站。见help center。也就是说,您是否想过为每个数字存储一位,并检查该位是否已设置?这样,您可以记录数量等于可用可用内存字节数的 8 倍的数字。java.util.BitSet
支持 2^31-1 数字,但您可以构建支持更多数字的东西。
地图不太合适
既然我们知道只有一个重复,我相信我们可以在看到重复的那一刻退出程序(尽管流中可能有更多数字),对吧?
@KedarMhaswade 当然可以,但关键是你怎么知道这个数字是重复的......
@shole,只是试图澄清要求。这是一个面试问题,所以应该问清楚的问题。
【参考方案1】:
这些整数有多大或多小?如果确定所有整数都在 2^30-1 到 -2^30 或更小的范围内,请尝试 java.util.BitSet。 2^31 位 = 2^28 字节 ~ 2^8 兆字节 = 256 兆字节。这足够小,可以存储在普通笔记本电脑的内存中。
假设整数在2^30-1到-2^30之间,方法简单;对于大数据集中的每个整数i,先设置j = i + 2^30,并检查bitSet.get(j)是否为真,如果为真,重复数为i,否则调用bitSet.set(j, true ) 并继续,直到找到重复项。如果整数在 0 到 2^31 -1 之间,情况类似。
BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream("a.txt"), StandardCharsets.UTF_8));
String line = null;
BitSet bitSet = new BitSet((1<<31)- 1);
while ((line = reader.readLine()) != null)
int i = Integer.parseInt(line);
boolean v = bitSet.get(i);
if (v)
System.out.println("the duplicate is " + i);
break;
else
bitSet.set(i);
reader.close();
如果范围稍微大一点,比如 0 到 2^34 - 1,一个可行的想法是复制粘贴 java.util.BitSet 类并对其进行一些修改以创建一个稍微不同的类;一个 long[] 数组最多可以存储 ((2^31 - 1) * 2^6 - 1) 位。普通计算机仍然可以为一个对象提供 2G 内存。
如果范围较大或者这个查重模块不能占用太多内存,请参考上面cmet中的问题Algorithm for detecting duplicates in a dataset which is too large to be completely loaded into memory
【讨论】:
以上是关于在非常大的数据集中查找重复项 [重复]的主要内容,如果未能解决你的问题,请参考以下文章