GRardB
GRardB

Reputation: 744

In less-than-linear time, find the duplicate in a sorted array

Today, an interviewer asked me this question. My immediate response was that we could simply do a linear search, comparing the current element with the previous element in the array. He then asked me how the problem could be solved in less-than-linear time.

Assumptions

Example array: [0,1,2,3,4,5,6,7,8,8,9]

I attempted to come up with a divide-and-conquer algorithm to solve this, but I'm not confident that it was the right answer. Does anyone have any ideas?

Upvotes: 11

Views: 9658

Answers (7)

Jayjeet Chakraborty
Jayjeet Chakraborty

Reputation: 51

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

Upvotes: 1

chenna
chenna

Reputation: 159

Difference between sum of given array elements and sum of 0 to n-1 natural numbers gives you the duplicated element. Sum of 0 to n-1 elements is (N * N-1)/2 example array is [0,1,2,3,4,5,6,7,8,8,9] sum of 0 to 9 natural numbers is : 45 sum of given array elements : 53 53-45 = 8 Which is the duplicated element

Upvotes: 1

JavaSa
JavaSa

Reputation: 6241

How about that? (recursion style)

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;

}

Upvotes: 0

user1106083
user1106083

Reputation: 29

The example array is a little bit different from your question. Since n is the length of array and there are one and only duplicate in array, the value of each element in array should be in [0,n-1].

If that is true, then this question is the same one with How to find a duplicate element in an array of shuffled consecutive integers?

The following code should find the duplicate in O(n) time and O(1) space.

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

Upvotes: -1

aioobe
aioobe

Reputation: 421080

I attempted to come up with a divide-and-conquer algorithm to solve this, but I'm not confident that it was the right answer.

Sure, you could do a binary search.

If arr[i/2] >= i/2 then the duplicate is located in the upper half of the array, otherwise it is located in the lower half.

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

Since the array between lower and upper is halved in each iteration, the algorithm runs in O(log n).

ideone.com demo in Java

Upvotes: 6

Daniel Fischer
Daniel Fischer

Reputation: 183958

If no number is missing from the array, as in the example, it's doable in O(log n) with a binary search. If a[i] < i, the duplicate is before i, otherwise it's after i.

If there is one number absent and one duplicate, we still know that if a[i] < i the duplicate must be before i and if a[i] > i, the absent number must be before i and the duplicate after. However, if a[i] == i, we don't know if missing number and duplicate are both before i or both after i. I don't see a way for a sublinear algorithm in that case.

Upvotes: 7

BrokenGlass
BrokenGlass

Reputation: 160942

Can be done in O(log N) with a modified binary search:

Start in the middle of the array: If array[idx] < idx the duplicate is to the left, otherwise to the right. Rinse and repeat.

Upvotes: 25

Related Questions