在小于线性的时间内,在排序的数组中找到副本

时间:2012-03-12 19:38:48

标签: arrays algorithm search language-agnostic data-structures

今天,一位采访者问我这个问题。我的直接反应是我们可以简单地进行线性搜索,将当前元素与数组中的前一个元素进行比较。然后他问我如何在不太线性的时间内解决问题。

假设

  • 数组已排序
  • 只有一个重复
  • 数组填充数字[0, n],其中n是数组的长度。

示例数组:[0,1,2,3,4,5,6,7,8,8,9]

我试图想出一个分而治之的算法来解决这个问题,但我不相信这是正确的答案。有没有人有任何想法?

7 个答案:

答案 0 :(得分:25)

可以使用修改后的二进制搜索在O(log N)中完成:

从数组中间开始:如果array [idx]< idx副本位于左侧,否则位于右侧。冲洗并重复。

答案 1 :(得分:7)

如果数组中没有数字丢失,如示例所示,它可以在O(log n)中使用二进制搜索。如果a[i] < i,则副本位于i之前,否则位于i之后。

如果缺少一个号码且一个号码重复,我们仍然知道如果a[i] < i副本必须在i之前且a[i] > i之前,则缺席号码必须在{{1}之前和之后的重复。但是,如果i,我们不知道在a[i] == i之前或i之后是否都缺少数字和重复。在这种情况下,我没有看到子线性算法的方法。

答案 2 :(得分:6)

  

我试图想出一个分而治之的算法来解决这个问题,但我不相信这是正确的答案。

当然,你可以进行二分搜索。

如果arr[i/2] >= i/2,则副本位于数组的上半部分,否则它位于下半部分。

while (lower != upper)
    mid = (lower + upper) / 2
    if (arr[mid] >= mid)
        lower = mid
    else
        upper = mid-1

由于lowerupper之间的数组在每次迭代中减半,因此算法在O(log n)中运行。

ideone.com demo in Java

答案 3 :(得分:1)

给定数组元素之和与0到n-1个自然数之和的差异为您提供了重复元素。 0到n-1个元素的和是(N * N-1)/ 2 示例数组是[0,1,2,3,4,5,6,7,8,8,9] 0到9个自然数的总和是:45 给定数组元素的总和:53 53-45 = 8哪个是重复元素

答案 4 :(得分:0)

示例数组与您的问题略有不同。由于n是数组的长度,并且在数组中只有一个副本,因此数组中每个元素的值应该在[0,n-1]中。

如果确实如此,则此问题与How to find a duplicate element in an array of shuffled consecutive integers?

相同

以下代码应在O(n)时间和O(1)空间中找到副本。

public static int findOnlyDuplicateFromArray(int[] a, boolean startWithZero){
    int xor = 0;
    int offset = 1;
    for(int i=0; i < a.length; i++){
        if(startWithZero)
            xor = xor ^ (a[i] + offset) ^ i;
        else
            xor = xor ^ a[i] ^ i;
        }
        if(startWithZero)
            xor = xor - offset;
    return xor;
}

答案 5 :(得分:0)

怎么样? (递归式)

public static int DuplicateBinaryFind(int[] arr, int left, int right)
{
   int dup =0;

   if(left==right)
   {
      dup = left;
   }
   else
   {
        int middle = (left+right)\2;
        if(arr[middle]<middle)
        {
          dup = DuplicateBinaryFind(arr,left, middle-1);

        }
        else
        {
           dup = DuplicateBinaryFind(arr, middle+1, right);
        }
   }

   return dup;

}

答案 6 :(得分:0)

#include <bits/stdc++.h>
using namespace std;

int find_only_repeating_element(int arr[] , int n){
int low = 0;
int high = n-1;
while(low <= high){
    int mid = low + (high - low)/2;
    if(arr[mid] == arr[mid + 1] || arr[mid] == arr[mid - 1]){
        return arr[mid];
    }
    if(arr[mid] < mid + 1){
        high = mid - 2;
    }else{
        low = mid + 1;
    }
   }
   return -1;
}

int main(int argc, char const *argv[])
{
int n , *arr;
cin >> n;
arr = new int[n];
for(int i = 0 ; i < n ; i++){
    cin >> arr[i];
}
    cout << find_only_repeating_element(arr , n) << endl;
    return 0;
}