【问题标题】:Programming Pearls: find one integer appears at least twice编程珍珠:找到一个整数至少出现两次
【发布时间】:2011-07-28 03:52:29
【问题描述】:

在2.6节和问题2中,原来的问题是这样的:

“给定一个包含 4,300,000,000 个 32 位整数的顺序文件,如何找到至少出现两次的文件?”

我对这个练习的问题是:上述问题的技巧是什么,这个问题属于哪种通用算法类别?

【问题讨论】:

  • 书中给出的解决方案是二分查找

标签: algorithm programming-pearls


【解决方案1】:

鸽笼原则——如果你在 M 个鸽笼中有 N 只鸽子,并且 N>M,那么一个洞里至少有 2 只鸽子。这组 32 位整数是我们的 2^32 个鸽笼,我们文件中的 43 亿个数字是鸽子。由于 4.3x10^9 > 2^32,我们知道有重复。

您可以应用此原则来测试我们正在寻找的副本是否在数字的子集中,代价是读取整个文件,而不是一次加载超过一点到 RAM 中 - 只需计算您在测试范围内看到数字的次数,并与该范围内的整数总数进行比较。例如,要检查 1,000,000 和 2,000,000(含)之间的重复项:

int pigeons = 0;
int pigeonholes = 2000000 - 1000000 + 1; // include both fenceposts
for (each number N in file) {
  if ( N >= 1000000 && N <= 2000000 ) {
    pigeons++
  }
}
if (pigeons > pigeonholes) {
  // one of the duplicates is between 1,000,000 and 2,000,000
  // try again with a narrower range
} 

选择要检查的范围有多大与要读取 16GB 数据的次数取决于您:)

就一般算法类别而言,这是一个组合(关于计数的数学)问题。

【讨论】:

    【解决方案2】:

    对整数进行排序并循环遍历它们以查看连续整数是否重复。如果您想在内存中执行此操作,则需要 16GB 内存,这在当今的机器上是可能的。如果这不可能,您可以使用合并排序对数字进行排序,并将中间数组存储到磁盘。

    我的第一次实现尝试是使用来自 unix 的 sortuniq 命令。

    【讨论】:

    • 这个问题是用有限的资源测试你的约束。说你的答案需要 x GB 的内存不符合问题的精神。
    【解决方案3】:

    如果你的意思是 32 位正整数, 我认为这个问题不需要一些特殊的算法 或技巧来解决。只需简单的观察即可得出预期的解决方案。

    我的观察是这样的,顺序文件将只包含 32 位整数(从 0 到 2 ^ 31 - 1)。假设你把所有的 在该文件中,您将得到 2 ^ 31 行。你可以看到 如果你再次输入这些正整数,你将得到 2 ^ 31 * 2 行 并且小于 4,300,000,000。

    因此,答案是从 0 到 2 ^ 31 - 1 的整个正整数。

    【讨论】:

    • 1) 这并没有给你数字本身 2) 32 位整数通常意味着 32 位,没有 31 位。
    • 1) 是的,我知道。 2)嗯..,32位整数是从0到2 ^ 31 - 1,而不是从0到2 ^ 32之类的。这就是为什么在我的帖子开头有一个 if 的原因。如果作者的意思是 32 个有符号正整数,而不是无符号整数,则此解决方案有效。
    • 数据值没有这样的限制——它们只是 32 位整数
    【解决方案4】:

    创建一个长度为 2^32 位(初始化为零)的位数组,大小约为 512MB,适合任何现代机器的 RAM。

    开始读取文件,int by int,检查与int的值相同索引的位,如果该位被设置,则发现重复,如果为零,则设置为1并继续下一个int来自文件。

    诀窍是找到合适的数据结构和算法。在这种情况下,所有内容都可以通过合适的数据结构装入 RAM,并且可以使用简单高效的算法。
    如果数字是 int64,您需要找到合适的排序策略或进行多次传递,具体取决于您有多少可用的额外存储空间。

    【讨论】:

    • 需要注意的是,这种方法还需要对数据结构进行位级访问。按位运算(
    • “将适合任何现代机器上的 RAM” 不是在本书出版时 :) 一般来说,这似乎更像是一个讨论问题,没有一个单一的最佳答案。 (不过我没看过这本书)但今天这是明智的策略,所以 +1
    • 这是一个潜在的解决方案,但该部分的作者促使我们以某种方式思考我们没有太多 RAM 并希望我们利用二进制搜索来解决问题。有人可以使用 B.Search 想出一个解决方案吗?
    猜你喜欢
    • 1970-01-01
    • 2012-08-13
    • 2013-10-24
    • 1970-01-01
    • 1970-01-01
    • 2011-12-08
    • 2016-11-04
    • 2012-10-26
    • 2016-05-27
    相关资源
    最近更新 更多