【问题标题】:Find missing number from 4 billion (again)从 40 亿中找到缺失的数字(再次)
【发布时间】:2012-04-27 15:10:15
【问题描述】:

一个被问了很多次的问题似乎即将在 40 亿个数字中检测到一个缺失的数字。
推荐的方法似乎是使用位集(当内存限制是问题的一部分时)。
一个示例帖子是这样的:find-an-integer-not-among-four-billion-given-ones,我也可以在 SO 中链接到更多。

我的问题如下:bitset 方法似乎隐含地假设数字是-负数。作为我链接到的帖子中的一个例子,Java中有这个代码sn-p:

int radix = 8; 
byte[] bitfield = new byte[0xffffffff/radix]; 
void F() throws FileNotFoundException{ 
    Scanner in = new Scanner(new FileReader("a.txt")); 
    while(in.hasNextInt()){ 
        int n = in.nextInt(); 
        bitfield[n/radix] |= (1 << (n%radix)); 
    } 

    for(int i = 0; i< bitfield.lenght; i++){ 
        for(int j =0; j<radix; j++){ 
            if( (bitfield[i] & (1<<j)) == 0) System.out.print(i*radix+j); 
        } 
    } 
} 

但是在 Java 中所有的整数都是有符号的。结果,发布的代码将因负数而中断。这个int n = in.nextInt(); 可以返回负数。

所以我想不知何故我的困惑是关于这种问题/练习的两个部分:
1)可以使用位集来表示负数吗?怎么样?
2)问题的解决方案是否与特定的编程语言有关?例如。在有无符号数字的 C++ 中,我想人们可以接受范围是非负数的假设。

有人可以帮我理解这个吗?

【问题讨论】:

  • 是什么阻止您将数字简单地视为long,并添加 2^31 以使它们全部为正数?
  • @OliCharlesworth:如果我这样做了,我不会得到 2 个数字(一个正数和一个负数)的相同位索引吗?然后我将如何找到丢失的一个?扫描时相应的位索引将设置为 true 但只有一个会出现
  • 我建议为 all 值添加偏移量,而不仅仅是负值。
  • @OliCharlesworth:我明白你的意思。但在这种情况下,我是对的。我链接到的帖子代码有问题。对吧?

标签: java algorithm optimization bit-manipulation


【解决方案1】:

试试

long n = in.nextInt() & 0xFFFFFFFFL; 
bitfield[(int) (n/radix)] |= (1 << (n%radix));

或使用

final int bits = 3; 

bitfield[(int) (n >>> bits)] |= (1 << (n & ((1 << bits) -1)));

稍后

System.out.print((int) (i*radix+j)); 

您可能会发现使用 and int[]long[] 比使用 byte[] 稍快

【讨论】:

  • 当你垂头丧气bitfield[(int) (n/radix)] 我们不能以负数结束吗?
  • 如果你有一个[0, 2^32) 的范围并将其除以 8,你会得到一个[0, 2^29) 的范围或最大约 5.12 亿。
  • +1:我现在明白了。我无法用bits=3 掌握解决方案。我假设即使使用这种方法,n 也被计算为方法 1?还有为什么int[]byte[] 快吗?
  • 在 32/64 系统上,内存字大小为 32/64 位,要提取一个字节,它必须读取该字,屏蔽掉要更改的字节,然后在字等,即相当类似于你必须做的改变一个字节的位。位的使用速度更快,因为移位和掩码比除法和模数更快。与从文件中读取文本或写入控制台相比,这是一个微不足道的区别,所以它真的是你自己的知识。
  • 所以in.nextInt() &amp; 0xFFFFFFFFL; 保证当您分配给 long 时符号位始终为零?这就是您最终得到 [0, 2^32) 的方式?
【解决方案2】:

嗯,有一个明显的解决方案:因为我们知道每个数字都有一个特定的范围 [a, b),您可以将下边界添加到所有数字,以获得有保证的正数。

现在这不适用于任意长的数字,但这通常不是问题

【讨论】:

  • add the lower boundary to all numbers to get guaranteed positive numbers.In the range [a,b) where it is [-2.147.483.648 , 2,147,483,648) 你指出的下限是多少?
  • @user384706 很明显-2^31(你甚至使用了相同的符号?)。由于 java 中没有无符号数字,因此您必须使用下一个更大的大小。如果您将 -2^31 添加到整数范围,您最终会得到 [0, 2^32),正如预期的那样。
  • 所以你是说翻译成 [0, 2^32)。我现在明白你的意思了。但是你是什么意思 doesn't work for arbitrarily long numbers, but then that's usually not a problem?能否请您详细解释一下这一点?
  • @user384706 如果您没有下限,则无法将其添加到所有数字。 IE。假设您的范围是整数(在数学意义上),没有“最小整数”可以添加以确保所有数字都是正数。但是,如果您的范围不受限制,那么您提出的问题就没有多大意义,所以那里没有问题。
猜你喜欢
  • 2014-05-11
  • 2013-10-24
  • 2011-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-01
  • 2015-03-12
  • 2013-09-26
相关资源
最近更新 更多