7

Source : Microsoft Interview Question

Given a sorted array, in which every element is present twice except one which is present single time, we need to find that element.

Now a standard O(n) solution is to do a XOR of list, which will return the unduplicated element (since all duplicated elements cancel out.)

Is it possible to solve this more quickly if we know the array is sorted?

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
Spandan
  • 2,128
  • 5
  • 25
  • 37
  • 7
    Do a binary "search" (rather traversal) on the array, check both neighbors, if bot are different from the middle value, you have the solution. This is `O(log n)`. –  Jun 14 '13 at 21:18
  • @H2CO3 how so? Wouldn't the neighbors always be different? – zw324 Jun 14 '13 at 21:20
  • @ZiyaoWei Nopeeeee! I just don't speak English. If the array is sorted, (`1 1 2 2 3 4 4`), then one neighbor is the same as the central value. –  Jun 14 '13 at 21:21
  • @H2CO3 Are you assuming that all the elements are consecutive? If not, how do you decide whether to check the low half or the high half? – jerry Jun 14 '13 at 21:22
  • @jerry sorted array = consecutive! – Sebastian Jun 14 '13 at 21:23
  • @jerry Uh, I don't get that. Could you please elaborate? –  Jun 14 '13 at 21:23
  • @H2CO3 I was asking if you were assuming that there were no skipped numbers (as in your example). Based on Daniel Fiscer's answer, I understand what you were thinking. I blame my illness :) – jerry Jun 14 '13 at 21:37
  • @jerry No, I wasn't - the "am I present twice in the array" aspect has little to nothing to do with the distance of consecutive elements :) The thing is that if the array is sorted, then equal elements are always neighbors - and my approach (ab)uses that fact ;) –  Jun 14 '13 at 21:54

3 Answers3

15

Yes, you can use the sortedness to reduce the complexity to O(log n) by doing a binary search.

Since the array is sorted, before the missing element, each value occupies the spots 2*k and 2*k+1 in the array (assuming 0-based indexing).

So you go to the middle of the array, say index h, and check either index h+1 if h is even, or h-1 if h is odd. If the missing element comes later, the values at these positions are equal, if it comes before, the values are different. Repeat until the missing element is located.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
6

Do a binary "search" (rather traversal) on the array, check both neighbors, if both are different from the value in the middle, you have the solution. This is O(log n).

2

Yes, The array is sorted so we can apply binary search to find the single element. Let's see the pattern of occurrence of single element. Total number of elements will be always odd and single element occurs only at even index

Total number of elements 9, single elements always present at even index

Total number of elements 9, single elements always present at even index. When (end_index - start_index) % 4 == 0, The single element is occurring in middle.

if A[mid-1] == A[mid] --> single element left side
if A[mid] == A[mid+1] --> single element right side

Total number of elements 11

Total number of elements 11, single elements always present at even index. When (end_index - start_index) % 4 != 0, The single element is not occurring in middle.

if A[mid] == A[mid+1] --> single element left
if A[mid-1] == A[mid] --> single element right

enter image description here

Total number of elements 13, single elements always present at even index. When (end_index - start_index) % 4 == 0, The single element is occurring at middle also.

if A[mid-1] == A[mid] --> single element left side
if A[mid] == A[mid+1] --> single element right side

Below is the Python Code:

class Solution:
    def singleNonDuplicate(self, A):
        """
        :type nums: List[int]
        :rtype: int
        """
        L = len(A)

        def binarySearch(A, start, end):
            if start == end:
                return A[start]

            if start < end:

                mid = int(start + (end - start)/2)

                if A[mid-1] < A[mid] < A[mid+1]:
                    return A[mid]
                if end - start == 2:
                    if A[end] != A[end-1]:
                        return A[end]
                if end - start == 2:
                    if A[start] != A[start+1]:
                        return A[start]
                if A[mid] == A[mid+1]:
                    if int(end-start)%4 == 0:
                        return binarySearch(A, mid+2, end)
                    else:
                        return binarySearch(A, start, mid-1)

                elif A[mid-1] == A[mid]:
                    if int(end - start)%4 == 0:
                        return binarySearch(A, start, mid-2)
                    else:
                        return binarySearch(A, mid+1, end)

        return binarySearch(A, 0, L-1)


if __name__ == "__main__":

    s = Solution()
    A = [1,1,2,3,3,4,4,5,5,6,6]
    r = s.singleNonDuplicate(A)
    print(r)
Siddharth Kumar
  • 2,672
  • 1
  • 17
  • 24