Arrays 在少于线性时间内,在排序数组中查找重复项

Arrays 在少于线性时间内,在排序数组中查找重复项,arrays,algorithm,search,language-agnostic,data-structures,Arrays,Algorithm,Search,Language Agnostic,Data Structures,今天,一位面试官问我这个问题。我的直接反应是,我们可以简单地进行线性搜索,将当前元素与数组中的前一个元素进行比较。然后他问我如何在不到线性时间内解决这个问题 假设 数组已排序 只有一个副本 数组仅填充有数字[0,n],其中n是数组的长度 示例数组:[0,1,2,3,4,5,6,7,8,8,9] 我试图想出一个分而治之的算法来解决这个问题,但我不相信这是正确的答案。有人有什么想法吗 我试图想出一个分而治之的算法来解决这个问题,但我不相信这是正确的答案 当然,你可以进行二进制搜索 如果arr[i

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

假设

  • 数组已排序
  • 只有一个副本
  • 数组仅填充有数字
    [0,n]
    ,其中
    n
    是数组的长度
示例数组:[0,1,2,3,4,5,6,7,8,8,9]

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

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

当然,你可以进行二进制搜索

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

while (lower != upper)
    mid = (lower + upper) / 2
    if (arr[mid] >= mid)
        lower = mid
    else
        upper = mid-1
由于
lower
upper
之间的数组在每次迭代中减半,因此该算法以O(logn)运行


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

如果缺少一个数字和一个副本,我们仍然知道如果
a[i]
副本必须在
i
之前,如果
a[i]>i
,缺少的数字必须在
i
之前,副本必须在之后。但是,如果
a[i]==i
,我们不知道丢失的数字和重复的数字是在
i
之前还是在
i
之后。在这种情况下,我看不到次线性算法的方法。

可以通过修改的二进制搜索在O(logn)中完成:


从数组的中间开始:如果数组[IDx] 示例数组与您的问题略有不同。因为n是数组的长度,并且数组中只有一个重复,所以数组中每个元素的值应该在[0,n-1]中

如果这是真的,那么这个问题与

下面的代码应该在O(n)时间和O(1)空间中找到副本

public static int findOnlyDuplicateFromArray(int[]a,boolean startWithZero){
int-xor=0;
int offset=1;
for(int i=0;i
怎么样?(递归风格)

公共静态int-duplicateBaryFind(int[]arr,int-left,int-right)
{
int-dup=0;
如果(左==右)
{
dup=左;
}
其他的
{
int middle=(左+右)\2;

if(arr[middle]给定数组元素之和与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哪个是重复元素

#包括
#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;
}
使用名称空间std; int find_only_repeating_元素(int arr[],int n){ int低=0; int高=n-1; 而(低>n; arr=新整数[n]; 对于(int i=0;i>arr[i]; }
很抱歉,这不是一个线性时间。应该使用二进制搜索来实现目标。线性时间不少于您的示例仅包括数字
[0,n-2]
(没有
10
11
),这只是一个示例还是一条一般规则?对于通用版本,它应该是
array[idx]-array[0]
。将所有元素相加就是O(n)-因此,在BuffGETI已经很晚了,但是如果你允许丢失的数字,这是不可能的(假设你不能在O(1)中读取任意数量的单元格)。假设我们考虑了大小为n+1(n>=2)的条目,并且我们将自己限定为条目的子集:{[0,0,2,…,n],[0,1,1,3,…,n],…,[0,1,…,k,k,k+2,…,n],…[0,1,…,n-1,n-1]}。假设您已经知道多达(n-2)个单元格中任何单元格的内容,并且它们是两两不同的,仍然存在至少2种可能性,并且您无法区分任何单元格。因此,您至少需要阅读(n-1)单元格来决定哪个数字是重复的。欢迎这么做。请在回答问题时考虑对代码添加一些解释。
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;

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