【问题标题】:Fastest way to find 2 missing numbers in an array在数组中查找 2 个缺失数字的最快方法
【发布时间】:2011-12-16 10:12:03
【问题描述】:

这个问题的存在只是因为纯粹的好奇。不是家庭作业。

找到在数组 1..n 中找到两个缺失数字的最快方法

所以,在相关帖子中:Quickest way to find missing number in an array of numbers 我发现你可以通过加总和减去总数来很快地做到这一点。

但是 2 个数字呢?

所以,我们的选择是:

  1. 顺序搜索
  2. 总结项目,从总数中减去 1..n 中的所有项目,然后搜索所有可能的情况。

还有什么? 可能有 O(n) 解决方案? 我在其中一个网站的 ruby​​ 部分发现了这一点,但可以考虑任何语言(除非语言有一些特定的东西)

【问题讨论】:

  • 您可以简单地对数组进行排序,这可以在 O(n log n) 中完成。之后,您可以遍历已排序的数据并检测数字 i 是否为 n+1。这将添加另一个 n,但仍会在 O(n log n) 中。
  • -1。你的问题不清楚。数组 1..n 中缺少数字是什么意思(可能您的意思是 (1..n).to_a)?它不包括所有这些吗?如果链接上有一些细节,它仍然没有帮助。您需要在这里清楚地陈述问题。
  • “最快”定义不明确。最快的算法和可能最快的 Ruby 实现,重复:stackoverflow.com/questions/3492302/…。最佳红宝石高尔夫球手:可能是 steenslag 的答案。

标签: ruby algorithm


【解决方案1】:
  1. 求数字之和S=a1+...+an
  2. 还求平方和T=a1*a1+...+an*an
  3. 你知道总和应该是S'=1+...+n=n(n+1)/2
  4. 你知道平方和应该是T'=1^2+...+n^2=n(n+1)(2n+1)/6
  5. 现在建立以下方程组 x+y=S'-S, x^2+y^2=T'-T.
  6. 通过写x^2+y^2=(x+y)^2-2xy => xy=((S'-S)^2-(T'-T))/2来解决。现在这些数字只是z:z^2-(S'-S)z+((S'-S)^2-(T'-T))/2=0 中的二次方的根。

【讨论】:

【解决方案2】:

简单的方法(也很快:)

a = [1,2,3,5,7]
b = (1..7).to_a
p b-a #=> [4, 6]

【讨论】:

  • @Michael J. Barber 数组 a 不必排序即可。
  • 这不是很快,因为它具有二次复杂性,并且有一个已知且非常简单的线性解决方案(请参阅下面的答案)。
【解决方案3】:

假设数组为 [1,4,2,3,7] 。缺少的数字是 5,6

第 1 步:将数组中的所有数字相加。 17. 我们知道 1..7 的总和 (n*(n+1)/2) = 28。

因此 x+y+17=28 => x+y=11

第 2 步:将数组中的所有数字相乘。 168. 我们知道 1..7 = 5040 的乘积。

因此 x*y*168 = 5040 => x*y=30

(x+y)^2 = x^2 + 2xy + y^2 
=> 121 = 60 + x^2 + y^2
=> x^2 + y^2 = 61

(x-y)^2 = x^2 - 2xy + y^2 
=> (x-y)^2 = 61 - 60
=> (x-y)^2 = 1 
=> x-y = 1

我们有 x+y=11 和 x-y=1。求解 x,y。

此解决方案不需要额外的内存空间,并且在 O(n) 内完成。

【讨论】:

  • 我喜欢这个解决方案! +1
  • 乘法很容易超过 Integer.MAX_VALUE
  • 这个很容易理解。
【解决方案4】:

我使用以下方法在我的测试中获得了最快的时间(比替换 2 个数组要快一点):

n = 10
input = [3, 6, 8, 2, 1, 9, 5, 7]

temp = Array.new(n+1, 0)
input.each { |item| temp[item] = 1 }
result = []
1.upto(n) { |i| result << i if temp[i] == 0 }

【讨论】:

    【解决方案5】:

    创建一组从 1 到 N 的数字。计算该组与数组中的一组数字的差。由于数字不同,结果将是缺少的数字。 O(N)时空。

    【讨论】:

    • 无论实现如何,集合创建或差异计算都比 O(N) 慢。
    • @yi_H 使用哈希表。或者,由于它是一个有限集,长度为 N 的数组。这两个都是 O(N)。
    【解决方案6】:

    如果您不知道数组中的数字是什么怎么办?如果你刚刚得到一个数组并告诉你缺少一个数字,但你不知道里面有什么数字,你可以使用这个:

    array = array.uniq.sort!  # Just to make sure there are no dupes and it's sorted.
    i = 0
    while i < n.length-1
      puts n[i] + 1 if n[i] + 1 != n[i+1]
      i+=1
    end
    

    【讨论】:

    • 这不是假设数字是 1 到 length-1 吗?不然,谁说少的不是-10
    【解决方案7】:
    public class TwoNumberMissing {
        int fact(int x) {
            if (x != 0)
                return x * fact(x - 1);
            else
                return 1;
        }
    
        public static void main(String[] args) {
            TwoNumberMissing obj = new TwoNumberMissing();
            int a[] = { 1, 2, 3, 4, 5 };
            int sum = 0;
            int sum_of_ab = 0;
            for (int i = 0; i < a.length; i++) {
                sum = sum + a[i];
            }
            int b[] = {4,5,3};
            int prod = 1;
            int sum1 = 0;
            for (int i = 0; i < b.length; i++) {
                prod = prod * b[i];
                sum1 = sum1 + b[i];
            }
            int ab = obj.fact(a.length) / prod;
            System.out.println("ab=" + ab);
            sum_of_ab = sum - sum1;
            int sub_of_ab = (int) (Math.sqrt(sum_of_ab * sum_of_ab - 4 * ab));
            System.out.println("sub_of_ab=" + sub_of_ab);
            System.out.println("sum_of_ab=" + sum_of_ab);
            int num1=(sum_of_ab+sub_of_ab)/2;
             int num2=(int)ab/num1;
             System.out.println("Missing number is "+num2+" and "+num1);
        }
    }
    

    输出:

    ab=2
    
    sub_of_ab=1
    
    sum_of_ab=3
    
    Missing number is 1 and 2
    

    【讨论】:

      【解决方案8】:

      我提出以下解决方案

      #Swift 上的二分法在数组中找到 2 个缺失的数字

      private func find(array: [Int], offset: Int, maximal: Int, missing: Int) -> [Int] {
      
          if array.count <= missing + 1 {
              var found = [Int]()
              var valid = offset + 1
      
              for value in array {
                  if value != valid + found.count {
                      found.append(valid)
                  }
                  valid += 1
              }
              return found
          }
      
          let maxIndex: Int = array.count
          let maxValue: Int = maximal - offset
      
          let midIndex: Int = maxIndex / 2
          let midValue: Int = array[midIndex - 1] - offset
      
          let lostInFirst: Int = midValue - midIndex
          let lostInSecond: Int = maxValue - maxIndex - lostInFirst
      
          var part1 = [Int]()
          var part2 = [Int]()
      
          if lostInFirst > 0 {
              let subarray = Array(array[0..<midIndex])
              part1 = find(array: subarray, offset: offset, maximal: midIndex + offset + lostInFirst + 1, missing: lostInFirst)
          }
      
          if lostInSecond > 0 {
              let subarray = Array(array[midIndex..<maxIndex])
              part2 = find(array: subarray, offset: midIndex + offset + lostInFirst, maximal: maximal, missing: lostInSecond)
          }
      
          return part1 + part2
      }
      

      【讨论】:

        【解决方案9】:
        If the array is sorted from 0 to N then you can compare the difference with index. The recursion function for this is O(logN)
        Pseudo code for it is: 
        // OffsetA will keep track of the index offset of our first missing Number
        // OffsetB will keep track of our second missing number
        // Both Offset are set to Zero on the first recursion call. 
        
        Missing( Array A , Array B , OffsetA,  OffsetB ){
        Add Array's A and B together. Will call it array C.// At the beginning Array B would be empty.
        
        BaseCase:  If array C.length is 2 return C
        
            M= C.length/2 
        
        // for the middle value.
        
            If (C[M] == M + OffsetA){ // This means that both the values that are missing are to the right side of the array.
               return Missing((Arrays.copyOfRange(C,M,C.length)),ArrayB,M + Of
        
            fsetA,OffsetB);
            }
        
            If (C[M] == M + OffsetA +2){// This means both our values are to the left side of the missing array
        
             return Missing((Arrays.copyOfRange(C,0,M)),ArrayB,OffsetA,OffsetB);
            }
        
        //This is the more complicated one.
        
        `If(C[M] == M + OffsetA + 1){` This means that their are values on both the left and right side of the array. So we have to check the the middle of the first half and the middle of the second half of the array and we send the two quarter parts into our Missing Function. The checks are pretty much the same as the if statements up top but you should be able to figure out them your self. It seems like a homework or interview question. 
        
        
        
        EDIT: There might me a small issue with the offset switching and I dont have time to change it now but you should be able to figure out the basic concept. 
        
        }
        

        【讨论】:

          【解决方案10】:

          我喜欢总结并将结果与​​预期值进行比较的想法。所以我的想法是将数组分成相等的部分,将它们相加,看看两边是否缺少一个数字。如果一半是正确的,您可以迭代另一半(包含两个缺失的数字.....从语言的角度来看这听起来很错误>.

          如果 abs(i-j) 很大 - 或者换句话说:当缺失的数字彼此相距很远时,这种方法非常快。

          【讨论】:

            猜你喜欢
            • 2011-01-07
            • 2013-11-30
            • 2014-01-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-04-27
            • 1970-01-01
            相关资源
            最近更新 更多