编程珍珠:在40亿个整数的文件中查找缺失的整数

时间:2013-10-16 08:21:59

标签: algorithm programming-pearls

问题:输入位于顺序文件中。该文件最多包含4亿个整数。找到缺失的整数。

根据我的理解

解决方案

  1. 制作两个临时文件,一个带前导0,另一个带前导1

  2. 两个MUST中的一个(4.3B鸽笼和4B鸽子)少于2B。 选择文件并重复步骤1& 2在第2位然后在第3位,依此类推......

  3. 这次迭代的最终条件是什么?

    此外,该书提到算法的效率为O(n) 但是,

    第1次迭代=> n探测操作
    第二次迭代=> n / 2探头操作



    n + n / 2 + n / 4 + ... 1 => nlogn ??

    我错过了什么吗?

2 个答案:

答案 0 :(得分:4)

您将检查这两个文件并选择具有最少元素的文件。

您将重复此过程,直到您完成所有32位,最后您将拥有0个元素的文件。这是其中一个缺失的数字应该是的地方。所以,如果你一直在跟踪你到目前为止已过滤的位数,你就会知道这个数字应该是多少。

请注意,这是为了找到 a (即“任意”)缺失的数字。如果给出一个(无序的)顺序列表40亿(不是2^32(4294967296))整数,其中一个缺失,你必须找到,这将无法工作,因为你可以切断正确的缺失整数开始。

此外:

n + n/2 + n/4 + ... 1 <= 2n

不是n log n

这是geometric sequence a = n, r = 1/2,可以使用以下公式计算:

n (1-(1/2)^m)
-------------
  1 - (1/2)

由于0 < (1/2)^m < 1代表任何正数m(自0 < 1/2 < 1起),我们可以说(1-r^m) < 1,因此我们可以说最大值是:

  n.1
-------
1 - 1/2

   n
= ---
  1/2

= 2n

答案 1 :(得分:2)

如果只有1个缺失值,则表示您具有以下条件:

  1. 文件包含从最低值N到最高值M的所有数字,除了其中一个数字。
  2. 文件无需排序
  3. 这些值中只有一个缺失(只是确定)
  4. 然后解决方案非常简单:

    将文件中的所有数字一起添加或异或 将你应该拥有的所有数字加在一起或者异或 丢失的数字是一个减去另一个(在ADD的情况下)或一个x或另一个。

    以下是您可以试用的LINQPad计划:

    void Main()
    {
        var input = new[] { 1, 2, 3, 4, 5, 6, 8, 9, 10 };
    
        var lowest = input[0];
        var highest = input[0];
        int xor = 0;
        foreach (var value in input)
        {
            lowest = Math.Min(lowest, value);
            highest = Math.Max(highest, value);
            xor ^= value;
        }
        int requiredXor = 0;
        for (int index = lowest; index <= highest; index++)
            requiredXor ^= index;
    
        var missing = xor ^ requiredXor;
        missing.Dump();
    }
    

    基本上,它会:

    1. 将文件中的所有值放在一起(值1)
    2. 同时查找最低和最高数字
    3. XOR从最低到最高(值2)的所有值
    4. 将两个值(值1和值2)放在一起以找到缺失值
    5. 此方法不会检测缺失值是否为最低值 - 1或最高值+ 1,例如,如果文件应该保持1..10但缺少10或1,则上述方法找不到它。

      这个解决方案是O(2n)(我们将数字循环两次),转换为O(n)。

      这是一个更完整的示例,显示了ADD和XOR解决方案(同样在LINQPad中):

      void Main()
      {
          var input = new[] { 1, 2, 3, 4, 5, 6, 8, 9, 10 };
          MissingXOR(input).Dump("xor");
          MissingADD(input).Dump("add");
      }
      
      public static int MissingXOR(int[] input)
      {
          var lowest = input[0];
          var highest = input[0];
          int xor = 0;
          foreach (var value in input)
          {
              lowest = Math.Min(lowest, value);
              highest = Math.Max(highest, value);
              xor ^= value;
          }
          int requiredXor = 0;
          for (int index = lowest; index <= highest; index++)
              requiredXor ^= index;
      
          return xor ^ requiredXor;
      }
      
      public static int MissingADD(int[] input)
      {
          var lowest = input[0];
          var highest = input[0];
          int sum = 0;
          foreach (var value in input)
          {
              lowest = Math.Min(lowest, value);
              highest = Math.Max(highest, value);
              sum += value;
          }
          var sumToHighest = (highest * (highest + 1)) / 2;
          var sumToJustBelowLowest = (lowest * (lowest - 1)) / 2;
          int requiredSum =  sumToHighest - sumToJustBelowLowest;
          return requiredSum - sum;
      }