在阵列中找到2个缺失数字的最快方法

时间:2011-12-16 10:12:03

标签: ruby algorithm

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

找到在数组1..n

中找到两个缺失数字的最快方法

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

但是2个数字呢?

所以,我们的选择是:

  1. 顺序搜索
  2. 总结项目,从1..n中的所有项目中减去总数,然后搜索所有可能的案例。
  3. 还有别的吗? 可能有O(n)解决方案吗? 我在其中一个网站的ruby部分找到了这个,但是考虑了任何语言(除非语言有一些特定的东西)

10 个答案:

答案 0 :(得分:29)

  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'-Sx^2+y^2=T'-T
  6. 撰写x^2+y^2=(x+y)^2-2xy =>解决问题xy=((S'-S)^2-(T'-T))/2。现在这些数字仅仅是zz^2-(S'-S)z+((S'-S)^2-(T'-T))/2=0中的二次方的根。

答案 1 :(得分:17)

简单的方法(也很快:)

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

答案 2 :(得分:6)

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

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

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

步骤2:将数组中的所有数字相乘。我们知道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)中完成。

答案 3 :(得分:1)

我通过以下方法获得了测试中最快的时间(比替换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 }

答案 4 :(得分:0)

创建一组数字1到N.使用数组中的数字集计算此集合的差异。由于数字不同,结果将是缺失的数字。 O(N)时间和空间。

答案 5 :(得分:0)

如果你不知道数组中的数字是什么怎么办?如果您刚刚获得一个阵列并告知有一个号码丢失,但您不知道那里有什么号码,您可以使用它:

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

我提出以下解决方案

#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
}

答案 8 :(得分:0)

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. 

}

答案 9 :(得分:-1)

我喜欢总结并将结果与​​预期值进行比较的想法。所以我的想法是将数组分成相等的部分,将它们相加,看看双方是否都缺少一个数字。如果一半是正确的,你可以迭代另一半(包含两个缺失的数字......从语言学的角度来看,这听起来是错误的&gt;。&lt;)直到你设法分开数字。

如果abs(i-j)很大 - 或者用文字表示:当丢失的数字彼此相距很远时,这种方法非常快。