【问题标题】:Given a file containing 4.30 billion 32-bit integers, how can we find a number, which has appeared at least twice?给定一个包含 43 亿个 32 位整数的文件,我们如何找到一个至少出现两次的数字?
【发布时间】:2016-05-27 16:40:10
【问题描述】:

我为此提出了分而治之的算法。只是想知道这是否可行?

第一个 mid 是从整数范围即 (0+(1>1 计算出来的,然后应用这个想法:从 start 到 mid 或从 mid 到 end 的数字范围总是小于比我们在考虑十亿数字时要考虑的数字,并且肯定会有一些数字会重复,因为与十亿数字相比,32 位整数的范围要小得多。

def get_duplicate(input, start, end):  
  while True:
    mid = (start >> 1) + end - (end >> 1)
    less_to_mid = 0
    more_to_mid = 0
    equal_to_mid = 0
    for data in input:
        data = int(data, 16)
        if data < mid:
            less_to_mid += 1
        elif data == mid:
            equal_to_mid += 1
        else:
            more_to_mid += 1
    if equal_to_mid > 1:
        return mid
    elif mid-start < less_to_mid:
        end = mid-1
    elif end-mid < more_to_mid:
        start = mid+1

with open("codes\output.txt", 'r+') as f:
  content = f.read().split()
  print(get_duplicate(content, 0, 1<<32-1))

我知道我们可以使用位数组,但我只是想了解您对此解决方案的看法,以及实施是否存在问题。

【问题讨论】:

  • 你计算过 2^32 吗?
  • 对它们进行排序,然后你只需要检查每个人与下一个。
  • @AntiHeadshot:排序需要更多的内存,而内存并不存在。
  • @nomanpouigt 您不必将所有内容加载到 ram 中进行排序。

标签: algorithm numbers numeric numerical-methods divide-and-conquer


【解决方案1】:

你的方法没问题。但您可能需要多次阅读输入内容才能找到答案。

这里有一个变种,它可以让你找到一个内存很少的重复项,但你只需要读取输入两次。

  1. 将整数数组A[65536] 初始化为零。
  2. 一一读出数字。每次读取一个数字x,将1 添加到A[x mod 65536]
  3. 读取结束时,至少有一个i,使得A[i]严格大于65536。这是因为65536 * 63356 &lt; 4.3 billion。假设A[i0] 大于65536
  4. 将数组A清零。
  5. 再读一遍数字,但这一次,只看那些数字x,这样x mod 65536 = i0。对于每个这样的x,将1 添加到A[x / 65536]
  6. 读取结束时,至少有一个j,使得A[j]严格大于1。那么65536 * j + i0这个数字就是最终的答案。

【讨论】:

  • 我认为只需一个 32 位整数就足以找出重复项,对吧?只需设置和测试方法,在设置之前只需测试该特定位是否已设置。如果设置了,那就是答案,如果没有设置,那就设置它。为什么是 500M?
  • @noman pouigt:一个 32 位整数是不够的。您需要 43 亿位来跟踪尽可能多的数字。仅仅因为 32 位可以有 43 亿个状态,并不意味着它可以跟踪 43 亿个项目的状态
  • 一个i 会更大 if “所有”32 位整数值至少出现一次 - 问题陈述没有提到。注意出现超过 1
  • @greybeard 在这种情况下,如果它等于 65537,我们可以停止,或者我们可以检查溢出并丢弃进一步的添加。没有?
【解决方案2】:

2^32 位内存对于现代系统来说没什么特别的。所以你必须使用bitset,这个数据结构每个数字只需要一个位,所有现代语言都有一个实现。想法是这样的——你只要记住一个数字是否已经被看到:

void print_twice_seen (Iterator &it)//iterates through all numbers
{
  std::bitset< (1L<<32) > seen;//bitset for 2^32 elements, assume 64bit system

  while(it.hasNext()){
       unsigned int val=it.next();//return current element and move the iterator
       if(seen[val])
           std::cout<<"Seen at least twice: "<<val<<std::endl;
       else
           seen.set(val, true);//remember as seen
  }
}

【讨论】:

  • 问题中提到我知道位设置方法。假设由于内存问题而无法使用位设置方法。有没有其他方法或者我的方法是否可行?
  • @noman pouigt 抱歉,不知何故忽略了最后一句话。但是 bitset 对于 2^32 个数字来说不是问题,它只需要大约 0.5G
猜你喜欢
  • 2011-07-28
  • 2017-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-15
  • 1970-01-01
相关资源
最近更新 更多